我一般对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结构是所有数据的所有者。是吗?
如何更正我的代码以进行编译?
感谢帮助。
答案 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>>,
}