如何在不出现 "use moved value" 错误的情况下绑定盒装结构的多个字段?
How to bind multiple fields of a boxed struct without getting "use moved value" error?
我正在尝试编写通用递归数据结构的代码。事实证明,我不能,因为当我想访问一个拥有的结构值的多个字段时,我碰壁了。
我定义了一个包含列表的结构:
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),
})))
}
嗯,不,还是一样的错误。显然这不再像 link 那样工作了。
我也试过使用 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
,因此我可以在不重命名的情况下以简短形式编写解构。
Non-lexical lifetimes,从 Rust 2018 开始可用,允许您的原始代码按原样编译:
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() {}
我正在尝试编写通用递归数据结构的代码。事实证明,我不能,因为当我想访问一个拥有的结构值的多个字段时,我碰壁了。
我定义了一个包含列表的结构:
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),
})))
}
嗯,不,还是一样的错误。显然这不再像 link 那样工作了。
我也试过使用 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
,因此我可以在不重命名的情况下以简短形式编写解构。
Non-lexical lifetimes,从 Rust 2018 开始可用,允许您的原始代码按原样编译:
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() {}