匹配枚举时无法移出借用的内容

Cannot move out of borrowed content when matching an enum

我正在尝试打印一棵树(现在是 LinkedList,但会修复):

use std::io;
use std::rc::Rc;

enum NodeKind {
    Branch(Rc<Node>),
    Leaf,
}

struct Node {
    value: i32,
    kind: NodeKind,
}

fn main() {
    let leaf = Node { value: 10, kind: NodeKind::Leaf };
    let branch = Node { value: 50, kind: NodeKind::Branch(Rc::new(leaf)) };
    let root = Node { value: 100, kind: NodeKind::Branch(Rc::new(branch)) };

    let mut current = root;
    while true {
        println!("{}", current.value);
        match current.kind {
            NodeKind::Branch(next) => {
                current = *next;
            }
            NodeKind::Leaf => {
                break;
            }
        }
    }

    let mut reader = io::stdin();
    let buff = &mut String::new();
    let read = reader.read_line(buff);
}

编译器说:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:24:27
   |
24 |                 current = *next;
   |                           ^^^^^ cannot move out of borrowed content

我只读取值,没有更改任何内容。我正在从对另一个值的引用中分配一个值,试图取消对 Rc<T> 值的引用并将其存储在本地 mut 变量中。

也许这样的事情可能会奏效:

while true {
    println!("{}", current.value);
    match &current.kind {
        &NodeKind::Branch(next) => {
            current = next;
        }
        &NodeKind::Leaf => {
            break;
        }
    }
}

或者也许

let mut current = &Rc::new(root);
while true {
    println!("{}", current.value);
    match current.kind {
        NodeKind::Branch(next) => {
            current = &next;
        }
        NodeKind::Leaf => {
            break;
        }
    }
}

但我得到了同样的错误加上 'next' does not live long enough

我还不能弄清楚 1) 的问题,但我确实找到了 2) 的答案。

在顶部,您需要使用:

use std::rc::Rc;

而不是

use std::rc;

显示错误是因为默认情况下 match 将执行移动。

移动值后(即未通过引用获取或调用采用 self 的方法)后续调用失败。您可能需要克隆,这是 属性 您的 structenum 所缺乏的。添加这些 (#[derive(Clone)) 并将 current = *next; 更改为 current = (*next).clone(); 后,您的程序将再次运行!

use std::io;
use std::rc::Rc;

#[derive(Clone)]
enum NodeKind {
    Branch(Rc<Node>),
    Leaf,
}

#[derive(Clone)]
struct Node {
    value: i32,
    kind: NodeKind,
}

fn main() {
    let leaf = Node { value: 10, kind: NodeKind::Leaf };
    let branch = Node { value: 50, kind: NodeKind::Branch(std::rc::Rc::new(leaf)) };
    let root = Node { value: 100, kind: NodeKind::Branch(std::rc::Rc::new(branch)) };

    let mut current = root;
    while true {
        println!("{}", current.value);
        match current.kind {
            NodeKind::Branch(next) => {
                current = (*next).clone();
            }
            NodeKind::Leaf => {
                break;
            }
        }
    }

    let reader = io::stdin();
    let buff = &mut String::new();
    let read = reader.read_line(buff);
}

Playground

如果你 let mut current = &root 那么你可以避免 clone() 按照下面 Vladimir 的回复 (playpen of Vladimir's version)。

这里不用clone,完全可以做你想实现的参考:

use std::rc::Rc;

enum NodeKind {
    Branch(Rc<Node>),
    Leaf,
}

struct Node {
    value: i32,
    kind: NodeKind,
}

fn main() {
    let leaf = Node { value: 10, kind: NodeKind::Leaf };
    let branch = Node { value: 50, kind: NodeKind::Branch(Rc::new(leaf)) };
    let root = Node { value: 100, kind: NodeKind::Branch(Rc::new(branch)) };

    let mut current = &root;
    loop {
        println!("{}", current.value);
        match current.kind {
            NodeKind::Branch(ref next) => {
                current = &**next;
            }
            NodeKind::Leaf => break,
        }
    }
}

您的代码唯一重要的变化是匹配中的模式是 ref next 并且 current&Node.

类型

ref 模式通过引用绑定它们的变量,即 next 具有类型 &Rc<Node>。要从中获取 &Node,您需要解引用它两次以获取 Node,然后再次引用以获取 &Node。由于 Deref 强制转换,也可以写成 current = &next,编译器会自动为您插入适当数量的 *

我也从 while (true) 更改为 loop,因为它更加地道并且有助于编译器推理您的代码。

所有树状结构的遍历在 Rust 中都是这样完成的。 ref 模式允许不移出变量,这在你只需要读取数据时是绝对必要的。您可以找到更多关于模式以及它们如何与所有权和借用交互的信息 here