你试图改变某些东西,同时在其他地方持有对它的共享引用。这是一个问题,因为 Rust 假设共享 (&) 引用后面的内容不会发生变异,以证明您的代码在多线程上下文和存在某些优化的情况下是正确的。
要修复它,您可以告诉编译器忘记多线程并跳过这些优化。一种方法是使用RefCell:
use std::cell::RefCell;
#[derive(Debug, Clone)]
struct Movement {
x: i32,
y: i32,
}
fn main() {
let mut current = Some(RefCell::new(Movement { x: 1, y: 2 }));
// ^^^^^^^^^^^^ put it in a `RefCell`
let mut stack = Vec::new();
stack.push(¤t);
// note: as_ref, not as_mut
current.as_ref().unwrap().borrow_mut().x = 2;
println!("m: {:?}", current);
println!("stack.m: {:?}", stack.pop());
current = None;
}
如果您需要在不同线程之间共享对象,您可能需要Mutex 或RwLock。如果要共享的东西是可以简单复制的,比如单个i32,您可以使用Cell<i32>(非线程安全)或AtomicI32(线程安全)。这些统称为内部可变性类型,因为它们允许通过共享引用来改变内部值。
但内部可变性只能让你走这么远。将局部变量的引用放在Vec 中不是很灵活,因为Vec 不能比它引用的任何变量都活得更久。一个常见的习惯是将对象移动到Vec 并使用索引而不是内置引用来访问它们。这是一种方法:
#[derive(Debug, Clone)]
struct Movement {
x: i32,
y: i32,
}
fn main() {
// this object will be moved into the vector
let temp = Some(Movement { x: 1, y: 2 });
let mut stack = Vec::new();
// now we set `current` to be the index of the object in the vector, and use
// `stack[current_index]` to refer to the object itself
let current_index = stack.len();
stack.push(temp);
// you could also do something like this to get a mutable reference, but it
// would prevent you from doing anything else with `stack` until you are done with
// `current` (`stack[current_index]` does not have this limitation):
//let current = stack.last_mut().unwrap()
stack[current_index].as_mut().unwrap().x = 2;
println!("m: {:?}", stack[current_index]);
println!("stack.m: {:?}", stack.pop());
}
还有更多选择。例如,您可以将RefCell 放在Rc(引用计数智能指针)中并克隆它以在Vec 和局部变量之间共享所有权。在没有关于您的目标的更多信息的情况下,我倾向于对Vec 进行索引,以避免共享突变的复杂性,但设计最终是您的选择。
另见