I have two structs. App
and Item
.
What I want to achieve is to store an Item
in the items
vector of the App
struct by passing a mutable reference to the Item
s constructor.
pub struct App<'a> {
items: Vec<&'a Item>
}
impl<'a> App<'a> {
pub fn new() -> App<'a> {
App { items: Vec::new() }
}
pub fn register_item(&mut self, item: &'a Item) {
self.items.push(item);
}
}
pub struct Item;
impl Item {
pub fn new(app: &mut App) -> Item {
let item = Item;
app.register_item(&item);
item
}
}
fn main() {
let mut app = App::new();
let item = Item::new(&mut app);;
}
The code thows the following error:
test.rs:8:28: 8:32 error: `item` does not live long enough
test.rs:8 app.register_item(&item);
Is there any way to do this?
While Rc
might be correct for your use case, it's good to understand why you are getting the error you are. Please read Why can't I store a value and a reference to that value in the same struct? as it has a much more in-depth discussion about why your code cannot work as-is. A simplified explanation follows.
Let's look at your constructor:
fn new(app: &mut App) -> Item {
let item = Item;
app.register_item(&item);
item
}
Here, we create a new Item
on the stack at some address. Let's pretend that address is 0x1000. We then take the address of item
(0x1000) and store it into the Vec
inside the App
. We then return item
to the calling function, which resides in a different stack frame. That means that the address of item
will change, which means that 0x1000 is no longer guaranteed to point to a valid Item
! This is how Rust prevents you from making whole classes of memory errors!
I'd say that you'd normally see this written as:
fn main() {
let item = Item;
let mut app = App::new();
app.register_item(&item);
}
This will have the same problem if you tried to return app
or item
from this function, as the address will change.
If you have a straight-forward tree structure, I'd advocate for simply letting the parent nodes own the children:
struct App {
items: Vec<Item>
}
impl App {
fn new() -> App {
App { items: Vec::new() }
}
fn register_item(&mut self, item: Item) {
self.items.push(item);
}
}
pub struct Item;
fn main() {
let mut app = App::new();
app.register_item(Item);
}
Simple solution is to use Rc
.
use std::rc::Rc;
pub struct Item;
impl Item {
pub fn new(app: &mut App) -> Rc<Item> {
let item = Rc::new(Item);
app.register_item(item.clone());
item
}
}
pub struct App {
items: Vec<Rc<Item>>
}
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With