在其他结构

时间:2015-05-29 20:20:14

标签: rust

我有两个结构。 AppItem

我想要实现的是通过将可变引用传递给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);

有没有办法做到这一点?

2 个答案:

答案 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>>
}

...