How to link multiple fields in a boxed structure without getting the "use moved value" error?

I am trying to encode a general recursive data structure. As it turned out, I canโ€™t, when I hit the wall, when I want to access several fields of the structureโ€™s own value.

I define a structure that will contain a list:

struct ListNode<T> { val: T, tail: List<T> } struct List<T>(Option<Box<ListNode<T>>>); 

An empty list is represented by List(None) .

I want to be able to add to the list:

 impl<T> List<T> { fn append(self, val: T) -> List<T> { match self { List(None) => List(Some(Box::new(ListNode { val: val, tail: List(None), }))), List(Some(node)) => List(Some(Box::new(ListNode { val: node.val, tail: node.tail.append(val), }))), } } } 

This fails with a clear error:

 error[E0382]: use of moved value: 'node' --> src/main.rs:17:23 | 16 | val: node.val, | -------- value moved here 17 | tail: node.tail.append(val), | ^^^^^^^^^ value used here after move | = note: move occurs because 'node.val' has type 'T', which does not implement the 'Copy' trait 

I was looking for ways to use more than one field of the structure and found the "Avoid partially moved values" error when using a structure with multiple fields , so I will do this:

 List(Some(node)) => { let ListNode { val: nval, tail: ntail, } = *node; List(Some(Box::new(ListNode { val: nval, tail: ntail.append(val), }))) } 

Well no, it's the same mistake. Apparently, this no longer works, as in the link.

I also tried using links:

 List(Some(node)) => { let ListNode { val: ref nval, tail: ref ntail, } = *node; List(Some(Box::new(ListNode { val: *nval, tail: (*ntail).append(val), }))) } 

This time the deconstruction passes, but the creation of a new node fails with:

 error[E0507]: cannot move out of borrowed content --> src/main.rs:21:26 | 21 | val: *nval, | ^^^^^ cannot move out of borrowed content error[E0507]: cannot move out of borrowed content --> src/main.rs:22:27 | 22 | tail: (*ntail).append(val), | ^^^^^^^^ cannot move out of borrowed content 

Am I missing something obvious here? If not, then how to access multiple fields of a structure that is not passed by reference? I am using Rust 1.1.

+7
struct rust ownership
source share
2 answers

There's some kind of weird interaction with Box going on. You need to add an intermediate let statement that decompresses the field.

 List(Some(node)) => { let node = *node; // this moves the value from the heap to the stack let ListNode { val, tail } = node; // now this works as it should List(Some(Box::new(ListNode { val: val, tail: tail.append(value) }))) } 

Note that I renamed the function argument to value , so I could write the destructuring in short form without renaming.

Try it on the playground.

+6
source share

Non-lexical lifetimes , starting with Rust 2018, allow your source code to compile as-is:

 struct ListNode<T> { val: T, tail: List<T> } struct List<T>(Option<Box<ListNode<T>>>); impl<T> List<T> { fn append(self, val: T) -> List<T> { match self { List(None) => List(Some(Box::new(ListNode { val: val, tail: List(None), }))), List(Some(node)) => List(Some(Box::new(ListNode { val: node.val, tail: node.tail.append(val), }))), } } } fn main() {} 
+1
source share

All Articles