Rust编译器抱怨代码中使用了已移动的值,但实际上并未移动。

3
Rust在循环中使用了已移动的值,导致出现错误提示:
#[derive(PartialEq, Eq)]
enum Animal {
    Dog,
    Cat,
}

fn dedup(animals: Vec<Animal>) -> Vec<Animal> {
    let mut stage = None;
    let mut outs = vec![];

    for x in animals {
        match stage {
            None => stage = Some(x),
            Some(a) => {
                if a != x {
                    outs.push(a);
                    stage = Some(x);
                }
            }
        }
    }
    if let Some(a) = stage {
        outs.push(a);
    }
    outs
}

错误信息是:
error[E0382]: use of moved value
  --> src/lib.rs:14:18
   |
14 |             Some(a) => {
   |                  ^ value moved here, in previous iteration of loop
   |

当我阅读这段代码时,我看到stage被移动到a中,然后可能被推送到outs中,然后再也没有被使用。为什么这会导致编译错误? Playground 有趣的是,以下替代方案可以正常工作:
            Some(a) if a != x => {
                    outs.push(a);
                    stage = Some(x);
            }
            _ => {}


注意:你可以通过简单匹配 outs.last() 来编写不带阶段的 dedupplayground)。当然,如果这不是一个练习,你应该直接调用 Vec::dedup - trent
1个回答

5

当你编写代码时

match stage {
    // ...
    Some(a) => {
        // ...
    }
}

你正在无条件地将值从“stage”中移出。不管块中的代码是否使用了“a”,Rust 只关心“stage”现在已经作废,不能再次使用。
原因是:
Some(a) if a != x => {
    outs.push(a);
    stage = Some(x);
}

之所以能够生效是因为将if放在模式中使其成为了一种条件移动。只有当 a != x 时才会移出a,并且当这种情况发生时,stage 总是被重新赋值。


2
非常明确地说,对于像我这样错过了5次要点的人来说:在原始代码中,当stageSome(a)a == x时,stage被移出而不是立即重新分配,因此它不能在下一次迭代中再次被移出。 - trent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接