在获取递归数据结构的所有权时,避免部分移动的值?

时间:2015-03-14 05:29:03

标签: recursion rust

假设我有一个像单链表一样的递归数据结构,我想编写一个递归函数来在最后一个节点之后插入一个值*:

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

问:如何避免编译错误抱怨node已被部分移动?

修复失败#1:通过取maybe_node: &mut Option<Box<Node>>来避免取得函数参数的所有权。失败,因为我需要添加一个新节点并将其传递回堆栈,如果我只有一个可变引用,那么我需要取消引用它,这会导致非法移出借来的值:

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

修复失败#2:返回对新节点的引用(fn ... -> &Box<Node>)。失败,因为新节点的活动时间不够长(或者至少,我无法确定如何为新节点指定生命周期,使其至少与它返回的引用一样长从功能)。

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

(*原始代码段是我试图对this red black tree implementationput()执行的Rust音译的简化版本。我意识到我在这里概述的最小例子将是更好的循环,但实际上我试图编写的代码不是这样。)

更新:我认为这不是`cannot move out of dereference of `&mut`-pointer` while building a sorted linked list的重复,因为a)我正在尝试处理不同的错误消息&amp; b)我的fn需要self - 而非&mut self。话虽如此,我可能会尝试重写它以取&mut self,所以感谢指针@shepmaster。

1 个答案:

答案 0 :(得分:0)

使用take()(本身在封面下使用mem::replace())获取选项的值:

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