我正在尝试创建一个 Rust 程序,其中包含一个人物向量,以及另一个引用上述人物的事件向量(例如出生和死亡)。
但是,我无法找到一种方法来同时 1)将人的所有权转移到一个向量,以及 2)将引用保存在另一个向量中。
下面我粘贴了一个高度简化的应用程序版本,其中包含我当前的问题和一些解决方法。
struct Person {
name: String
}
enum Event<'a> {
PersonBorn(i32, &'a Person),
PersonDied(i32, &'a Person),
}
struct Universe<'a> {
people: Vec<Person>,
events: Vec<Event<'a>>
}
fn main() {
let mut data = Universe {
people: Vec::new(),
events: Vec::new()
};
let names = ["John", "Joe"];
for name in names {
let year = 1993;
let person = Person {
name: String::from(name)
};
data.people.push(person);
// Attempt 1: Doesn't work because "person" was moved on "push' on line 29
data.events.push(Event::PersonBorn(year, &person));
// Attempt 2: Doesn't work because it's an immutable borrow of "data",
// while doing a mutable borrow on line 29
// data.events.push(Event::PersonBorn(year, &data.people.last().unwrap()));
}
// Attempt 3: In this simplified example, this works, but in my real
// program I would not know the year anymore at this point
//for person in data.people.iter() {
// data.events.push(Event::PersonBorn(year, person));
//}
for event in data.events {
match event {
Event::PersonBorn(year, person) => println!("{} was born in {}", person.name, year),
Event::PersonDied(year, person) => println!("{} died in {}", person.name, year),
}
}
}
现在,我明白了为什么尝试 1(移动后借用)和尝试 2(for 循环中的可变和不可变引用)会失败。
但是,我能想到的唯一解决方法是尝试 3,但这在实际应用中是不可行的。
还有其他我没见过的方法可以做到这一点吗?
可以说,问题可以追溯到这个
struct
定义:这将要求所拥有字段的内容
events
指向所拥有people
字段的内容。如果这确实以某种方式起作用,则调用universe.people.clear()
将创建悬空引用。因此,这struct
是自引用的,不可能的。保留您的意图的一个简单方法是使用以下形式的引用计数
Rc
:现在,无论字段发生什么情况
people
,Event
都有Rc
对 的有效 -引用Person
。这是因为Rc
会保持其内容有效,直到最后一个Rc
-引用被删除。另一种方法是创建
PersonId
标量类型并将存储Person
在中HashMap
: