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

标签 enums rust

我正在尝试打印一棵树(现在是 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

最佳答案

这里不需要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 nextcurrent类型为 &Node .

ref模式通过引用绑定(bind)它们的变量,即 next类型为 &Rc<Node> .获取&Node从中,您需要取消引用它两次才能获得 Node然后再次引用得到&Node .由于 Deref 强制转换,也可以写成 current = &next , 编译器将插入适当数量的 * s 自动为您服务。

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

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

关于enums - 匹配枚举时无法移出借用的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30463490/

相关文章:

C++ 异常处理和枚举作用域

c++ - 通过枚举模板化的类调用方法

java - 枚举有什么用?

compilation - 你如何根据目标三元组有条件地编译?

string - 将 Vec<u16> 或 Vec<WCHAR> 转换为 &str

java - 通过通用方法访问 Java 中的各种枚举

c - _BIG_ENUM=0xFFFFFFFF 在枚举的最后是什么意思?

closures - 如何在 Rust 中捕获闭包范围之外的变量?

rust - 如何在我的项目中不显式定义新依赖项的情况下使用另一个 crate 中的 crate?

macros - 具有不同类型的可变参数的宏