将实现特征的数据存储在向量中

时间:2019-02-20 14:13:18

标签: pointers vector rust traits lifetime

我一般对Rust和系统语言都是新手。我目前正在与Rust一起探索语言。我有一个自己无法解决的问题。而且我认为我已经了解了发生了什么问题。

我不会在向量中存储实现trait BaseStuff的对象。在Rust中,对我来说,这不是一个简单的任务:-)。

这是我无法编译的示例代码。

trait BaseStuff {}

struct MyStuff {
    value: i32,
}

struct AwesomeStuff {
    value: f32,
    text: String,
}

impl BaseStuff for MyStuff {}

impl BaseStuff for AwesomeStuff {}

struct Holder {
    stuff: Vec<BaseStuff>,
}

impl Holder {
    fn register(&mut self, data: impl BaseStuff) {
        self.stuff.push(data);
    }
}

fn main() {
    let my_stuff = MyStuff { value: 100 };

    let awesome_stuff = AwesomeStuff {
        value: 100.0,
        text: String::from("I'm so awesome!"),
    };

    let mut holder = Holder { stuff: vec![] };

    holder.register(my_stuff);
}
  

错误[E0277]:类型(dyn BaseStuff + 'static)的值的大小   编译时无法知道-> src \ main.rs:17:5 | 17 |
  东西:Vec,//未知大小| ^^^^^^^^^^^^^^^^^^^^^^   在编译时没有已知的大小| =帮助:特质   std::marker::Sized未实现(dyn BaseStuff + 'static) =注意:要了解更多信息,请访问   https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait   =注意:std::vec::Vec的必需

     

错误:由于先前的错误而中止

     

有关此错误的更多信息,请尝试rustc --explain E0277。   错误:无法编译playground

     

编译器消息很清楚,我理解该消息。我可以   我不想在任何结构中实现特征BaseStuff   它是什么尺寸。顺便说一句,该链接没有帮助,因为它指向   过时的网站...

String的大小也不知道,但是String实现了特征std::marker::Sized,这就是Vec<String>可以正常工作的原因。正确吗?

在锈书中,我读取了未知大小的数据类型,我必须将这些数据存储在堆中而不是堆栈中。我如下更改了代码。

struct Holder {
    stuff: Vec<Box<BaseStuff>>,
}

impl Holder {
    fn register(&mut self, data: impl BaseStuff) {
        self.stuff.push(Box::new(data));
    }
}

现在我遇到了一个新的编译器问题:

  

错误[E0310]:参数类型impl BaseStuff可能寿命不长   足够-> src \ main.rs:22:25 | 21 | fn register(&mut self,   数据:impl BaseStuff){|
  ---------------帮助:考虑添加一个明确的生命周期约束impl BaseStuff: 'static ... 22 | self.stuff.push(Box :: new(data));
  | ^^^^^^^^^^^^^^ |注意:...这样   类型impl BaseStuff将符合其所需的生存期边界->   src \ main.rs:22:25 | 22 | self.stuff.push(Box :: new(data));
  | ^^^^^^^^^^^^^^^

     

错误:由于先前的错误而中止

     

有关此错误的更多信息,请尝试rustc --explain E0310。   错误:无法编译playground

并且知道我不在...我在书中读到了有关寿命的信息,并在这里用'a'a任意组合但没有运气,对代码进行了很多更改……我不不想写下我尝试过的任何生命周期定义组合。 我不明白为什么我需要生命周期定义。所有权在任何步骤中都可以移动,因此据我所知,Holder结构是所有数据的所有者。是吗?

如何更正我的代码以进行编译?

感谢帮助。

1 个答案:

答案 0 :(得分:2)

几乎知道了-这里的问题是,实现了BaseStuff的类型可能是引用(例如impl BaseStuff for &SomeType)。这意味着即使您通过值传递data,该值也可能是您的Box所用的引用。

解决此问题的方法是添加一个约束,以使对象具有'static的生存期,这意味着它将成为值类型或静态引用。您可以根据用例将此约束应用于特征或接受特征的方法。

将约束应用于特征:

trait BaseStuff: 'static {}

将约束应用于方法:

impl Holder {
    fn register(&mut self, data: impl BaseStuff + 'static) {
        self.stuff.push(Box::new(data));
    }
}

如果将'static约束添加到方法中,我建议也将其添加到Vec中,以避免丢失类型信息,例如:

struct Holder {
    stuff: Vec<Box<dyn BaseStuff + 'static>>,
}