【问题标题】:Avoid partially moved value when taking ownership of a recursive data structure?在获得递归数据结构的所有权时避免部分移动值?
【发布时间】:2015-03-14 05:29:02
【问题描述】:

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

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: &amp;mut Option&lt;Box&lt;Node&gt;&gt;。失败,因为我需要添加一个新节点并将其传回堆栈,如果我只有一个可变引用,那么我需要取消引用它,这会导致非法移出借来的值:

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 ... -&gt; &amp;Box&lt;Node&gt;)。失败,因为新节点的生命周期不够长(或者至少,我不知道如何指定新节点的生命周期,以便它的生命周期至少与返回的引用一样长从函数)。

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

(* 原始的 sn-p 是我尝试对 this red black tree implementationput() 进行的 Rust 音译的简化版本。我意识到我在这里概述的最小示例会更好一个循环,但我实际尝试编写的代码并非如此。)

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

【问题讨论】:

标签: recursion rust


【解决方案1】:

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

【讨论】:

  • 啊,take() 成功了。我更新了我的问题以更详细地说明为什么将节点作为第一个参数引用似乎不起作用(以及使代码的意图更清晰),因此我将更新您的答案以显示已修复版本使用take() 来适应。
猜你喜欢
  • 2021-11-08
  • 2015-10-07
  • 2021-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-31
  • 2018-09-10
相关资源
最近更新 更多