gpt4 book ai didi

rust - 如何在 Vec 中存储引用并稍后在 Rust 中使用它?

转载 作者:行者123 更新时间:2023-12-03 11:34:04 25 4
gpt4 key购买 nike

我需要创建一个 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(&current);

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(&current);

// note: as_ref, not as_mut
current.as_ref().unwrap().borrow_mut().x = 2;

println!("m: {:?}", current);
println!("stack.m: {:?}", stack.pop());
current = None;
}

如果您需要在不同线程之间共享对象,您可能需要 MutexRwLock。如果共享的东西是可以简单复制的东西,比如单个 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 以避免共享突变的复杂性,但设计最终是您的选择。

另见

关于rust - 如何在 Vec 中存储引用并稍后在 Rust 中使用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63404153/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com