我有两个结构.App和Item.
我想要实现的是通过将可变引用传递给s构造函数来在结构Item的items向量中存储.AppItem
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);;
}
Run Code Online (Sandbox Code Playgroud)
该代码产生以下错误:
test.rs:8:28: 8:32 error: `item` does not live long enough
test.rs:8 app.register_item(&item);
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点?
虽然Rc对于您的用例可能是正确的,但是理解为什么您会收到错误是很好的.请阅读为什么我不能在同一个结构中存储值和对该值的引用?因为它有更深入的讨论,为什么你的代码不能按原样运行.简化说明如下.
我们来看看你的构造函数:
fn new(app: &mut App) -> Item {
let item = Item;
app.register_item(&item);
item
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们Item在某个地址的堆栈上创建一个新的.我们假装地址是0x1000.然后我们取item(0x1000)的地址并将其存储在Vec内部App.然后我们返回item到调用函数,该函数驻留在不同的堆栈帧中.这意味着地址item会改变,这意味着0x1000不再保证指向有效Item!这就是Rust阻止你制作整类内存错误的方法!
我会说你通常会把它写成:
fn main() {
let item = Item;
let mut app = App::new();
app.register_item(&item);
}
Run Code Online (Sandbox Code Playgroud)
如果您尝试返回app或item从此功能返回,则会出现相同的问题,因为地址会发生变化.
如果你有一个直接的树结构,我主张简单地让父节点拥有子节点:
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);
}
Run Code Online (Sandbox Code Playgroud)