取消引用一个盒装结构并移动它的字段会导致它被移动,但以另一种方式执行它可以正常工作。我不明白这两个pop
函数之间的区别。当另一个没有失败时,如何失败?
pub struct Stack<T> {
head: Option<Box<Node<T>>>,
len: usize,
}
struct Node<T> {
element: T,
next: Option<Box<Node<T>>>,
}
impl<T> Stack<T> {
pub fn pop(&mut self) -> Option<T> {
self.head.take().map(|boxed_node| {
let node = *boxed_node;
self.head = node.next;
node.element
})
}
pub fn pop_causes_error(&mut self) -> Option<T> {
self.head.take().map(|boxed_node| {
self.head = (*boxed_node).next;
(*boxed_node).element
})
}
}
error[E0382]: use of moved value: `boxed_node`
--> src/main.rs:22:13
|
21 | self.head = (*boxed_node).next;
| ------------------ value moved here
22 | (*boxed_node).element
| ^^^^^^^^^^^^^^^^^^^^^ value used here after move
|
= note: move occurs because `boxed_node.next` has type `std::option::Option<std::boxed::Box<Node<T>>>`, which does not implement the `Copy` trait
答案 0 :(得分:4)
您只能移出一个方框:
struct S;
fn main() {
let x = Box::new(S);
let val: S = *x;
let val2: S = *x; // <-- use of moved value: `*x`
}
在第一个函数中,您将值移出框并将其分配给node
变量。这允许您从中移出不同的字段。即使移动了一个字段,其他字段仍然可用。相当于:
struct S1 {
a: S2,
b: S2,
}
struct S2;
fn main() {
let x = Box::new(S1 { a: S2, b: S2 });
let tmp: S1 = *x;
let a = tmp.a;
let b = tmp.b;
}
在第二个函数中,将值移动到临时(*boxed_node)
,然后移出一个字段。临时值在表达式结束后立即销毁,以及其他字段。该框不再具有数据,并且您没有变量来从中获取其他字段。相当于:
struct S1 {
a: S2,
b: S2,
}
struct S2;
fn main() {
let x = Box::new(S1 { a: S2, b: S2 });
let tmp: S1 = *x;
let a = tmp.a;
let tmp: S1 = *x; // <-- use of moved value: `*x`
let b = tmp.b;
}
答案 1 :(得分:0)
一些好消息是non-lexical lifetimes将允许您的原始代码运行:
#![feature(nll)]
pub struct Stack<T> {
head: Option<Box<Node<T>>>,
len: usize,
}
struct Node<T> {
element: T,
next: Option<Box<Node<T>>>,
}
impl<T> Stack<T> {
pub fn pop_no_longer_causes_error(&mut self) -> Option<T> {
self.head.take().map(|boxed_node| {
self.head = (*boxed_node).next;
(*boxed_node).element
})
}
}
NLL增强了借阅检查器,以更好地跟踪变量的移动。