Cannot move out of borrowed content when matching an enum

前端 未结 3 890
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-20 21:53

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 {
    Branc         


        
相关标签:
3条回答
  • 2020-12-20 22:22

    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,
            }
        }
    }
    

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

    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.

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

    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.

    0 讨论(0)
  • 2020-12-20 22:33

    The error is displayed because by default match will perform a move.

    After a value is moved (i.e. wasn't taken by reference or method that takes self was called) subsequent calls fail. You'll probably need to clone, which is a property both of your struct and enum lack. Once you add those (#[derive(Clone)) and change current = *next; into current = (*next).clone();, your program will work again!

    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

    If you let mut current = &root then you can avoid clone() as per Vladimir's response below (playpen of Vladimir's version).

    0 讨论(0)
  • 2020-12-20 22:35

    I can't figure out the issue with 1) yet, but I did find an answer for 2).

    At the top, you need to use:

    use std::rc::Rc;

    instead of

    use std::rc;

    0 讨论(0)
提交回复
热议问题