簡體   English   中英

Rust trait 問題 trait 不能變成一個對象

[英]Rust trait issues trait cannot be made into an object

我正在嘗試編寫一些代碼來生成具有隨機值的隨機結構。 我有以下結構的特征和幫助宏:

use rand::{thread_rng, Rng};
use std::fmt;

pub trait DataType {
    /// generate a new instance of the type with a random value
    fn random() -> Box<Self>;
    /// generate a new instance of the same type with a random value
    fn gen_another(&self) -> Box<Self>;
}

macro_rules! impl_data_type_for_num {
    ($x:ident) => {
        impl DataType for $x {
            fn random() -> Box<Self> {
                Box::new(Self {
                    value: thread_rng().gen()
                })
            }

            fn gen_another(&self) -> Box<Self> {
                Self::random()
            }
        }
    };
}

macro_rules! impl_formatting {
    ($x:ident, $s:expr) => {
        impl fmt::Debug for $x {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $s)
            }
        }

        impl fmt::Display for $x {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{}", self.value)
            }
        }
    };
}

然后我使用宏在一堆結構上實現所需的特征(例如,這里有一些):

pub struct VirtBool {
    value: bool
}
impl_data_type_for_num!(VirtBool);
impl_formatting!(VirtBool, "bool");

pub struct VirtU8 {
    value: u8
}
impl_data_type_for_num!(VirtU8);
impl_formatting!(VirtU8, "u8");

pub struct VirtU16 {
    value: u16
}
impl_data_type_for_num!(VirtU16);
impl_formatting!(VirtU16, "u16");

到目前為止一切正常,但是當我嘗試在具有未大小字段的結構上實現相同的特征時出現問題:

pub struct VirtArray {
    _type: Box<dyn DataType>,
    value: Vec<Box<dyn DataType>>
}
impl DataType for VirtArray {
    fn random() -> Box<Self> {
        let t = random_var();
        let s = thread_rng().gen_range(0, 10);
        Box::new(Self {
            _type: *t,
            value: (0..s).map(|_| t.gen_another()).collect()
        })
    }

    fn gen_another(&self) -> Box<Self> {
        Box::new(Self {
            _type: self._type,
            value: self.value.iter().map(|t| t.gen_another()).collect::<Vec<Box<dyn DataType>>>()
        })
    }
}
impl fmt::Debug for VirtArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{:?}; {}]", self._type, self.value.len())
    }
}
impl fmt::Display for VirtArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = self.value.iter().map(|v| format!("{}, ",v)).collect::<String>();
        s.truncate(s.len().checked_sub(2).unwrap_or(s.len()));
        write!(f, "[{}]", s)
    }
}

這會引發錯誤, the trait 'DataType' cannot be made into an object多次the trait 'DataType' cannot be made into an object 然后我有一個函數來創建一個隨機結構,但這也會引發相同的錯誤:

/// generate a random type with random value
fn random_var() -> Box<dyn DataType> {
    match thread_rng().gen_range(0,4) {
        0  => Box::new(VirtBool::random()),
        1  => Box::new(VirtU8::random()),
        2  => Box::new(VirtU16::random()),
        3  => Box::new(VirtArray::random()),
        _  => panic!("invalid")
    }
}

我最初使用枚舉來完成所有這些,但我試圖將其切換到結構和特征以幫助擴展/使用能力。 有誰知道如何修復上面的代碼? 我在這里遇到了一個障礙已經有一段時間了。

另外,我知道我可以使用type_name_of_val來打印類型,但我試圖避免使用不穩定/夜間功能。

DataType不能被做成 trait 對象,因為它使用Self並且因為它有一個靜態方法。

我意識到返回Box<Self>似乎可以合理地調用dyn DataType ,因為如果您在dyn DataType上調用它,您需要一個Box<dyn DataType> ,但 Rust 不會嘗試為您修改方法將返回例如Box<VirtArray>轉換為返回Box<dyn DataType>如果它們在dyn DataType值上被調用。 您可以通過讓方法返回Box<dyn DataType>來解決此問題。

trait 對象不允許使用靜態方法,因為 trait 對象類型沒有實現。 請記住, dyn Foo實現了Foo (dyn DataType)::random()會是什么? (您可以使用 where 子句,如上例所示,以確保dyn DataType不會以可以提前檢測到的方式使用此方法;這意味着您不能在dyn DataType上使用它對象,但聽起來您可能不想這樣做。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM