4
votes

Say I have a recursive data structure like a singly-linked list, and I want to write a recursive function to insert a value after the last node*:

struct Node {
    next: Option<Box<Node>>,
    val: i32,
}

fn put_after_node(maybe_node: Option<Box<Node>>, val: i32) -> Box<Node> {
    match maybe_node {
        None => Box::new(Node { next: None, val: val }),
        Some(mut node) => {
            // compile error on next line: use of partially moved value: `node`
            node.next = Some(put_after_node(node.next, val));
            node
        }
    }
}

Q: How do I avoid the compile error complaining that node has been partially moved?

Failed fix #1: Avoiding taking ownership of the function's arguments, by taking maybe_node: &mut Option<Box<Node>> instead. Failed because I need to add a new node and pass that back up the stack, and if I only have a mutable reference then I need to dereference it, which causes an illegal move out of borrowed value:

fn put_after_node(maybe_node: &mut Option<Box<Node>>, val: i32) -> Box<Node> {
    match maybe_node {
        &mut None => Box::new(Node { next: None, val: val }),
        &mut Some(ref mut node) => {
            node.next = Some(put_after_node(&mut node.next, val));
            *node // compile error: cannot move out of borrowed content
        }
    }
}

Failed fix #2: Return a reference to a new node instead (fn ... -> &Box<Node>). Failed because the new node doesn't live long enough (or at least, I can't work out how to specify the lifetime for the new node such that it does live at least as long as the reference to it that'd be returned from the function).

fn put_after_node(maybe_node: &mut Option<Box<Node>>, val: i32) -> &Box<Node> {
    match maybe_node {
        // compile error on next line: borrowed value does not live long enough
        &mut None => &Box::new(Node { next: None, val: val }),
        &mut Some(ref mut node) => {
            // compile error on next line: cannot move out of borrowed content
            node.next = Some(*put_after_node(&mut node.next, val));
            node
        }
    }
}

(* The original snippet is a simplified version of a Rust transliteration that I'm attempting to do of this red black tree implementation's put(). I realise that the minimal example I've outlined here would be better as a loop, but that isn't the case for the code I'm actually trying to write.)

Update: I don't think this is a dup of `cannot move out of dereference of `&mut`-pointer` while building a sorted linked list because a) I'm trying to deal with a different error message & b) my fn takes self - not &mut self. Having said that, I will probably try to rewrite it to take &mut self, so thanks for the pointer @shepmaster.

1

1 Answers

0
votes

Take the Option's value using take() (which itself uses mem::replace() under the covers):

fn put_after_node(maybe_node: Option<Box<Node>>, val: i32) -> Box<Node> {
    match maybe_node {
        None => Box::new(Node { next: None, val: val }),
        Some(mut node) => {
            // note the node.next.take()
            node.next = Some(put_after_node(node.next.take(), val));
            node
        }
    }
}