将值传递给 Enum 变体时出现 Rust 'use of moved value' 错误

Rust 'use of moved value' error when passing value into Enum variant

我对 Rust 很陌生(才几天)。当然,我已经被所有权的概念困住了。

我有一个相当冗长的问题,所以这里是我使用的所有相关声明:

pub struct ThePrimaryStruct<'a> {
    frames: Vec<Frame<'a>>,
    stack: Vec<Object<'a>>,
    ip: usize
}

pub struct FunctionObject<'a> {
    pub min_arity: i32,
    pub max_arity: i32,
    pub chunk: Chunk<'a>,
    pub name: &'a str,
}

pub struct Frame<'a> {
    pub function: FunctionObject<'a>,
    // ... other struct members
}

pub struct Chunk<'a> {
    pub codes: Vec<OpCode>, // OpCode is an enum
    pub locations: Vec<(i64, i64)>,
    pub constants: Vec<Object<'a>>
}

pub enum Object<'a> {
    Function(FunctionObject<'a>),
    // Other enum variants
}

以上代码没有问题。当我为 ThePrimaryStruct 实现以下方法时出现问题:

pub(crate) fn the_function(&mut self, source: &'a str) -> SomeResult {
    // `Compiler::compile()` returns a FunctionObject struct.
    let func: FunctionObject = Compiler::compile(source);

    // The enum variant `Object::Function` takes ownership of `func`
    // The code works fine up until this point.
    self.stack.push(Object::Function(func));

    self.frames.push(Frame {
        // The struct member `function` should have the
        // exact same value as the one we just pushed into
        // the `self.stack` vector.
        function: func, // <---- Source of conflict
        // ... other struct members
    });

    self.run() // self.run() returns `SomeResult`
}

运行 这会导致错误:

error[E0382]: use of moved value: `func`
   |
37 |         let func: FunctionObject = Compiler::compile(source);
   |             ---- move occurs because `func` has type `FunctionObject<'_>`, which does not implement the `Copy` trait
...
40 |         self.stack.push(Object::Function(func));
   |                                          ---- value moved here
...
44 |             function: func,
   |                       ^^^^ value used here after move

我明白为什么会出现这个错误(或者至少我想我明白了):Object::Function 变体取得 func 的所有权,然后在我们完成推送对象时从内存中删除进入 self.stack。然后这会与 Frame 结构的初始化产生冲突,因为我试图使用一个不再存在的值。

我已经尝试为结构 FunctionObject 实现 Copy 特性,但这会产生更多问题,因为 FunctionObject 有一个 Chunk<'a> 类型的成员,它本身有向量成员。

编辑: 克隆绝对可以解决问题。但是,通过克隆 FunctionObject,我将复制 chunk 中的数据,它可以是任意长的大小。在使用 Object::Function(&func)stack 和使用 Frame { function: &func, ... }frame 中引用 FunctionObject 会导致 'func' does not live long enough 错误。

我正在尝试做的事情是否存在根本性错误?

您似乎有一个 FunctionObject 想要同时存储在 stackframe 中。 更好的解决方案可能是不将 FunctionObject 直接存储在堆栈和帧上,而是使用 smart pointers

我将向您展示一个使用 Rc 的解决方案,但是,您似乎在制作一个编译器,因此您可能需要一个不同的数据结构来存储您的函数对象,例如 arena .

下面的代码只包括我对你原来的修改,不过你也可以看看on the playground where I got it to compile:

pub struct Frame<'a> {
    pub function: std::rc::Rc<FunctionObject<'a>>,
    // ... other struct members
}

pub enum Object<'a> {
    Function(std::rc::Rc<FunctionObject<'a>>),
    // Other enum variants
}

pub(crate) fn the_function(&mut self, source: &'a str) -> SomeResult {
    // `Compiler::compile()` returns a FunctionObject struct.
    let func: FunctionObject = Compiler::compile(source);
    let func = std::rc::Rc::new(func);
    
    
    // The enum variant `Object::Function` takes ownership of `func`
    // The code works fine up until this point.
    self.stack.push(Object::Function(func.clone()));

    self.frames.push(Frame {
        // The struct member `function` should have the
        // exact same value as the one we just pushed into
        // the `self.stack` vector.
        function: func, // <---- No longer source of conflict
        // ... other struct members
    });

    self.run() // self.run() returns `SomeResult`
}

Rc 通过引用计数来管理一个对象。 当删除最后一个 Rc 时,值 (FunctionObject) 也将被删除。 在 func 上使用 .clone() 复制引用并增加计数,但不复制基础对象。