取消引用盒装结构并移动其字段会导致它被移动

时间:2016-10-29 12:57:03

标签: rust

取消引用一个盒装结构并移动它的字段会导致它被移动,但以另一种方式执行它可以正常工作。我不明白这两个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

2 个答案:

答案 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增强了借阅检查器,以更好地跟踪变量的移动。