我有两个结构。 App
和Item
。
我想要实现的是通过将可变引用传递给Item
构造函数,将items
存储在App
结构的Item
向量中。
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);;
}
代码显示以下错误:
test.rs:8:28: 8:32 error: `item` does not live long enough
test.rs:8 app.register_item(&item);
有没有办法做到这一点?
答案 0 :(得分:5)
虽然rptInventory
可能对您的用例而言是正确的,但很好理解为什么您会收到错误。请阅读Why can't I store a value and a reference to that value in the same struct?,因为它对您的代码无法正常工作的原因进行了更深入的讨论。简化说明如下。
让我们看看你的构造函数:
Rc
在这里,我们在某个地址的堆栈上创建一个新的fn new(app: &mut App) -> Item {
let item = Item;
app.register_item(&item);
item
}
。我们假装地址是0x1000。然后,我们将Item
(0x1000)的地址存储到item
内的Vec
中。然后我们将App
返回到调用函数,该函数驻留在不同的堆栈框架中。这意味着item
的地址将发生变化,这意味着不再保证0x1000指向有效的item
!这就是Rust阻止你制造整类内存错误的方法!
我会说你通常会把它写成:
Item
如果您尝试从此功能返回fn main() {
let item = Item;
let mut app = App::new();
app.register_item(&item);
}
或app
,则会出现同样的问题,因为地址会发生变化。
如果你有一个直接的树结构,我主张简单地让父节点拥有子节点:
item
答案 1 :(得分:1)
简单的解决方案是使用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>>
}
...