Unable to exit borrowed content when matching enumeration

I am trying to print a tree (this is a LinkedList right now, but it 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); } 

The compiler says:

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

I read only the value without changing anything. I am assigning a value from a reference to another value, trying to dereference the value of Rc<T> and store it in a mut local variable.

maybe something like this might work:

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

or maybe

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

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

+5
source share
3 answers

There is no need to clone, it is absolutely possible to do what you want to get with links:

 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 to your code are that the pattern in the match ref next and current is of type &Node .

ref templates bind their variables by reference, that is, next is of type &Rc<Node> . To get &Node from it, you need to dereference it twice to get Node , and then get &Node again. Due to coercion, Deref can also write current = &next , and the compiler automatically inserts the corresponding number * .

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

All tree structure walks are performed as follows in Rust. ref templates allow you to not move from variables, which is absolutely necessary when you only need to read data. You can find more about templates and how they interact with ownership and borrowing here .

+7
source

The error is displayed because by default match will execute the move.

After moving the value (that is, it was not obtained by reference or by a method that accepts self ), subsequent calls fail. You will probably have to clone, which is a property of both your struct and enum . When you add those ( #[derive(Clone) ) and change current = *next; on 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() according to Vladimir's answer below ( playpen version of Vladimir ).

+2
source

I still can not understand the problem with 1), but I found the answer for 2).

At the top you should use:

use std::rc::Rc;

instead

use std::rc;

+1
source

All Articles