首页 > 解决方案 > 为什么当我用一个新值替换它时,Rust 编译器会抱怨我使用了一个移动的值?

问题描述

我正在研究两个单链表,名为longershorter. 一个的长度longer保证不小于shorter一个。

我将列表元素配对,并对每一对做一些事情。如果longer列表中有更多未配对的元素,则处理其余元素:

struct List {
    next: Option<Box<List>>,
}

fn drain_lists(mut shorter: Option<Box<List>>, mut longer: Option<Box<List>>) {
    // Pair the elements in the two lists.
    while let (Some(node1), Some(node2)) = (shorter, longer) {
        // Actual work elided.
        shorter = node1.next;
        longer = node2.next;
    }
    // Process the rest in the longer list.
    while let Some(node) = longer {
        // Actual work elided.
        longer = node.next;
    }
}

但是,编译器在第二个 while 循环中抱怨

error[E0382]: use of moved value
  --> src/lib.rs:13:20
   |
5  | fn drain_lists(mut shorter: Option<Box<List>>, mut longer: Option<Box<List>>) {
   |                                                ---------- move occurs because `longer` has type `std::option::Option<std::boxed::Box<List>>`, which does not implement the `Copy` trait
6  |     // Pair the elements in the two lists.
7  |     while let (Some(node1), Some(node2)) = (shorter, longer) {
   |                                                      ------ value moved here
...
13 |     while let Some(node) = longer {
   |                    ^^^^ value used here after move

但是,我确实shorter在循环结束时为and设置了一个新值longer,这样我就永远不会使用它们的移动值。

我应该如何迎合编译器?

标签: rust

解决方案


我认为问题是由第一个循环中的临时元组引起的。创建一个元组会将其组件移动到新元组中,即使随后的模式匹配失败也会发生这种情况。

首先,让我编写一个更简单的代码版本。这编译得很好:

struct Foo(i32);
fn main() {
    let mut longer = Foo(0);
    while let Foo(x) = longer {
        longer = Foo(x + 1);
    }
    println!("{:?}", longer.0);
}

但是如果我添加一个临时的 while let然后我会触发一个类似于你的编译器错误:

fn fwd<T>(t: T) -> T { t }
struct Foo(i32);
fn main() {
    let mut longer = Foo(0);
    while let Foo(x) = fwd(longer) {
        longer = Foo(x + 1);
    }
    println!("{:?}", longer.0);
    //        Error: ^ borrow of moved value: `longer`
}

解决方案是添加一个带有要解构的值的局部变量,而不是依赖临时变量。在您的代码中:

struct List {
    next: Option<Box<List>>
}

fn drain_lists(shorter: Option<Box<List>>,
               longer: Option<Box<List>>) {
    // Pair the elements in the two lists.
    let mut twolists = (shorter, longer);
    while let (Some(node1), Some(node2)) = twolists {
        // Actual work elided.
        twolists = (node1.next, node2.next);
    }
    // Process the rest in the longer list.
    let (_, mut longer) = twolists;
    while let Some(node) = longer {
        // Actual work elided.
        longer = node.next;
    }
}

推荐阅读