I'm very new to Rust and system languages in general. And I'm currently playing around with Rust to explore the language. I've a problem that I cannot fix by myself. And I think I've understanding problem whats going on.
I wan't to store objects that implements the trait BaseStuff
in a vector. In Rust not a simple task for me :-).
Here is my example code that won't compile.
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);
}
error[E0277]: the size for values of type
(dyn BaseStuff + 'static)
cannot be known at compilation time --> src\main.rs:17:5 | 17 |
stuff: Vec, // unknown size | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the traitstd::marker::Sized
is not implemented for(dyn BaseStuff + 'static)
= note: to learn more, visit https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait = note: required bystd::vec::Vec
error: aborting due to previous error
For more information about this error, try
rustc --explain E0277
. error: Could not compileplayground
.The compiler message is clear and I understand the message. I can implement the trait BaseStuff in any struct I want't so its unclear which size it is. Btw the link isn't helpful because its pointing to outdated site...
The size of String is also unknown, but the String implements the trait std::marker::Sized
and that's why a Vec<String>
will work without problems. Is that correct?
In the rust book I read for data types with unknown size I've to store these data on the heap instead of the stack. I changed my code as follows.
struct Holder {
stuff: Vec<Box<BaseStuff>>,
}
impl Holder {
fn register(&mut self, data: impl BaseStuff) {
self.stuff.push(Box::new(data));
}
}
Now I'm hitting a new compiler issue:
error[E0310]: the parameter type
impl BaseStuff
may not live long enough --> src\main.rs:22:25 | 21 | fn register(&mut self, data: impl BaseStuff) { |
--------------- help: consider adding an explicit lifetime boundimpl BaseStuff: 'static
... 22 | self.stuff.push(Box::new(data));
| ^^^^^^^^^^^^^^ | note: ...so that the typeimpl BaseStuff
will meet its required lifetime bounds --> src\main.rs:22:25 | 22 | self.stuff.push(Box::new(data));
| ^^^^^^^^^^^^^^error: aborting due to previous error
For more information about this error, try
rustc --explain E0310
. error: Could not compileplayground
.
And know I'm out... I read in the book about lifetimes and changed my code a lot with 'a
here and 'a
in any combination but without luck... I don't want to write down any lifetime definition combination I tried.
I don't understand why I need the lifetime definition. The ownership is moved in any step so for my understanding its clear that Holder struct is the owner for all data. Is it?
How can I correct my code to compile?
Thanks for help.
fn register(&mut self, data: Box<BaseStuff> )
, please check the playground. – Ömer Erden