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

Jer*_*iel 3 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(&current);

   current.as_mut().unwrap().x = 2;

   println!("m: {:?}", current);
   println!("stack.m: {:?}", stack.pop());
   current = None;
}
Run Code Online (Sandbox Code Playgroud)

tre*_*tcl 6

您试图改变某些东西,同时在其他地方保留对它的共享引用。这是一个问题,因为 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;
}
Run Code Online (Sandbox Code Playgroud)

如果您需要在不同线程之间共享对象,您可能需要使用MutexorRwLock来代替。如果共享的东西是可以简单复制的东西,比如单个i32,你可以使用Cell<i32>(非线程安全) 或AtomicI32(线程安全)。这些统称为内部可变类型,因为它们允许通过共享引用改变内部值。

但内部可变性只能让你到目前为止。将局部变量的引用放入 a 中Vec并不是很灵活,因为 a 的Vec寿命不能比它引用的任何变量都长。常见的习惯用法是将对象移动到 a 中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());
}
Run Code Online (Sandbox Code Playgroud)

还有更多选择。例如,您可以将 放入RefCellRc引用计数智能指针)并克隆它以在Vec和局部变量之间共享所有权。在缺乏有关您的目标的更多信息的情况下,我倾向于索引Vec以避免共享突变的复杂性,但设计最终是您的选择。

也可以看看