匹配一个枚举时,不能移出借用的内容 [英] Cannot move out of borrowed content when matching an enum

查看:92
本文介绍了匹配一个枚举时,不能移出借用的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在打印一张树(现在是一张 LinkedList ,但这将被修复):

I'm trying to print out a tree (it's a LinkedList right now, but that will be fixed):

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 变量。

I'm reading the value only, not changing anything. I'm assigning a value from a reference to another value, trying to dereference an Rc<T> value and store it in a local mut variable.

可能这样可能会起作用:

maybe something like this may work:

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'不能长时间生活

but I get the same error plus 'next' does not live long enough

推荐答案

没有需要在这里克隆,绝对有可能通过引用来做你想要实现的内容:

There is no need to clone here, it is absolutely possible to do what you want to achieve with references:

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 当前的类型为 & Node

The only important changes from your code is that the pattern in the match is ref next and current is of type &Node.

ref 模式通过引用绑定其变量, next 具有类型& Rc< Node> 。要从中获取& Node ,您需要取消引用两次以获取 Node ,然后再次引用获取&安培;节点。由于Deref强制,也可以写入 current =& next ,编译器将插入适当数量的 * s自动为您。

ref patterns bind their variables by reference, that is, next has type &Rc<Node>. To get &Node from it, you need to dereference it two times to get Node and then reference again to get &Node. Due to Deref coercions, it is also possible to write current = &next, and the compiler will insert an appropriate number of *s for you automatically.

我也从 while(true)更改为循环,因为它更加惯用,它有助于编译器对代码进行推理。

I also changed from while (true) to loop because it is more idiomatic and it helps the compiler to reason about your code.

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

All traversals of tree-like structures are done like this in Rust. ref patterns allow not to move out of variables, which is absolutely necessary when you only need to read data. You can find more about patterns and how they interact with ownership and borrowing here.

这篇关于匹配一个枚举时,不能移出借用的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆