如何解决如何在Vec中存储引用,并稍后在Rust中使用它?
我需要创建一个Vec来跟踪正在创建的对象,并更改其状态以供以后使用。但是,如果在将对象存储在vec上时使用克隆,它的状态不会更新,该怎么做?
#[derive(Debug,Clone)]
struct Movement {
x: i32,y: i32,}
fn main() {
let mut current = Some(Movement { x: 1,y: 2 });
let mut stack = Vec::new();
stack.push(¤t);
current.as_mut().unwrap().x = 2;
println!("m: {:?}",current);
println!("stack.m: {:?}",stack.pop());
current = None;
}
解决方法
您正试图在某些地方保留对它的共享引用时进行某些更改。这是一个问题,因为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,}
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
编制索引,以避免共享突变的复杂性,但是最终还是由您选择设计。
另请参见
- Cannot borrow as mutable because it is also borrowed as immutable(以及相关链接的问题)
- How to represent shared mutable state?
- Situations where Cell or RefCell is the best choice
- Need holistic explanation about Rust's cell and reference counted types
要获取对vec中某个值的可变引用,您可以执行以下操作:
let idx = stack.len() - 1;
if let Some(pos) = stack.get_mut(idx) {
pos.x = 2
} else {
..
}
这专门获取您用vec
放在stack.push(current)
中的最后一个对象。请注意,然后我将对象完全移动到vec
中,而不仅仅是引用它们,并使用上述方法访问它们。
这是您的示例,为此进行了更正:
#[derive(Debug,Clone)]
struct Movement {
x: i32,}
fn main() {
let mut stack = Vec::new();
stack.push(Movement { x: 1,y: 2 });
let idx = stack.len()-1;
let mut current = stack.get_mut(idx).unwrap();
current.x = 2;
println!("m: {:?}",current);
println!("stack.m: {:?}",stack.pop());
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。