struct - 如何在不出现 "use moved value"错误的情况下绑定(bind)盒装结构的多个字段?

标签 struct rust ownership

我正在尝试编写通用递归数据结构的代码。事实证明,我不能,因为当我想访问一个拥有的结构值的多个字段时,我会碰壁。

我定义了一个包含列表的结构:

struct ListNode<T> {
    val: T,
    tail: List<T>
}

struct List<T>(Option<Box<ListNode<T>>>);

空列表由 List(None) 表示。

我希望能够附加到列表中:

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

此操作失败并出现可理解的错误:

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

我寻找使用一个结构的多个字段的方法,我发现 Avoiding partially moved values error when consuming a struct with multiple fields ,所以我会这样做:

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

嗯,不,还是一样的错误。显然这不再像链接中那样工作了。

我也试过使用 refs:

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

这次解构通过了,但是新节点的创建失败了:

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

我在这里遗漏了什么明显的东西吗?如果不是,访问未通过引用传递的结构的多个字段的正确方法是什么?我正在使用 Rust 1.1。

最佳答案

Box 发生了一些奇怪的交互。您需要添加一个中间 let 语句来打开盒子。

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

请注意,我将您的函数参数重命名为 value,因此我可以在不重命名的情况下以简短形式编写解构。

Try it out in the playground.

关于struct - 如何在不出现 "use moved value"错误的情况下绑定(bind)盒装结构的多个字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31391581/

相关文章:

rust - 关于 Rust 中的借用的困惑

rust - 重复更新和输出数据结构

networking - rust 迹所有权问题

c - 向结构数组添加新条目会覆盖所有最后的条目

c - 指向结构的指针数组的动态分配

mongodb - 通过 mgo v2(golang、mongoDB)更新结构的数组元素

rust - Rust 中带有私有(private)类型的显式类型注释

rust - 返回对可变引用结构的字段的可变引用

c - 使用结构和枚举洗牌

rust - libwasm_bindgen-a2e136f9a24e6618.rlib 挂起,编译时不占用 CPU