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);
}
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'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 ¤t.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
There is no need to clone here, it is absolutely possible to do what you want to achieve with references:
The only important changes from your code is that the pattern in the match is
ref next
andcurrent
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 getNode
and then reference again to get&Node
. Due to Deref coercions, it is also possible to writecurrent = &next
, and the compiler will insert an appropriate number of*
s for you automatically.I also changed from
while (true)
toloop
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.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;
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 yourstruct
andenum
lack. Once you add those (#[derive(Clone)
) and changecurrent = *next;
intocurrent = (*next).clone();
, your program will work again!Playground
If you
let mut current = &root
then you can avoidclone()
as per Vladimir's response below (playpen of Vladimir's version).