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

时间:2015-05-21 05:11:51

标签: 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

3 个答案:

答案 0 :(得分:8)

这里没有必要克隆,绝对可以通过引用来实现你想要的目标:

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进行交互的更多信息。

答案 1 :(得分:3)

显示错误,因为默认情况下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,那么您可以根据弗拉基米尔的回复(playpen of Vladimir's version)来避免clone()

答案 2 :(得分:1)

我无法弄清楚1)的问题,但我找到了2)的答案。

在顶部,您需要使用:

use std::rc::Rc;

而不是

use std::rc;