将结构的引用存储在其他结构中
我有两个结构体.App
和 Item
.
I have two structs. App
and Item
.
我想要实现的是通过将可变引用传递给 App
结构的 items
向量中存储 Item
code>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);;
}
代码提示以下错误:
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?
虽然 Rc
可能适用于您的用例,但最好理解为什么会出现这样的错误.请阅读为什么我不能在同一个结构中存储一个值和对该值的引用?,因为它有很多更深入地讨论为什么您的代码不能按原样工作.下面是一个简单的解释.
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
}
在这里,我们在堆栈上的某个地址创建了一个新的 Item
.让我们假设地址是 0x1000.然后我们将 item
的地址(0x1000)存储到 App
内的 Vec
中.然后我们将 item
返回给调用函数,该函数位于不同的堆栈帧中.那意味着item
的地址会改变,也就意味着0x1000不再保证指向一个有效的Item
!这就是 Rust 防止你犯整类内存错误的方式!
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);
}
如果你试图从这个函数返回 app
或 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);
}