我可以用借来的元素改变向量吗?



我试图存储对可变向量元素的引用以供稍后使用。但是,一旦改变了向量,就不能再使用存储的引用了。我理解这是因为借用对元素的引用也需要借用对向量本身的引用。因此,不能修改vector,因为这需要借用一个可变引用,当已经借用了另一个vector引用时,不允许这样做。

下面是一个简单的例子

struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Person> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| Person {
name: s.to_string(),
})
.collect();
// Borrow a reference to an element
let person_ref = &people[0];
// Mutate the vector
let new_person = Person {
name: "Tim".to_string(),
};
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}

会产生以下错误

error[E0502]: cannot borrow `people` as mutable because it is also borrowed as immutable
--> src/main.rs:21:5
|
15 |     let person_ref = &people[0];
|                       ------ immutable borrow occurs here
...
21 |     people.push(new_person);
|     ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
24 |     assert!(person_ref.name == "Joe");
|             --------------- immutable borrow later used here

我也试过按照这里的建议将vector元素装箱,但是没有帮助。我认为它可能允许我在保留对元素的引用的同时删除对vector的引用,但显然不是。

struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Box<Person>> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| {
Box::new(Person {
name: s.to_string(),
})
})
.collect();
// Borrow a reference to an element
let person_ref = people[0].as_ref();
// Mutate the vector
let new_person = Box::new(Person {
name: "Tim".to_string(),
});
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}

这仍然会产生相同的错误

error[E0502]: cannot borrow `people` as mutable because it is also borrowed as immutable
--> src/main.rs:23:5
|
17 |     let person_ref = people[0].as_ref();
|                      ------ immutable borrow occurs here
...
23 |     people.push(new_person);
|     ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
26 |     assert!(person_ref.name == "Joe");
|             --------------- immutable borrow later used here

有办法做到这一点,还是我试图做一些不可能的事情?

我发现使用引用计数的智能指针可以让我完成我正在尝试的事情。共享所有权是有意义的,因为如果原始向量超出作用域,元素引用将无效(这将释放元素,无论是否有Box)。

下面的代码编译成功。

use std::rc::Rc;
struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Rc<Person>> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| {
Rc::new(Person {
name: s.to_string(),
})
})
.collect();
// Borrow a reference to an element
let person_ref = Rc::clone(&people[0]);
// Mutate the vector
let new_person = Rc::new(Person {
name: "Tim".to_string(),
});
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}

如果有人有任何更正、改进或进一步的见解,我很高兴听到。但如果不是,我对这个答案感到满意。

虽然Oliver给出的答案似乎是最好的解决方案,

但是,如果我们只想改变向量(如问题标题所述),即不推入任何其他元素(因为向量的处理很复杂),只是修改值,则可以使用Vec给出的split_at_mut()函数。

let (head, tail) = people.split_at_mut(1);

现在我们可以让某些东西借头而我们改变尾巴。但是我们不能推到它,因为头和尾都是切片。

最新更新