'&&x' 模式匹配是否会导致 x 被复制?

har*_*mic 4 reference pattern-matching rust

std::iter::Iterator::filter()的文档中,它解释了值是通过引用传递给闭包的,并且由于许多迭代器产生引用,在这种情况下传递的值是对引用的引用。它提供了一些改进人体工程学的建议,方法是使用一种&x模式来删除一个间接级别,或者使用一种&&x模式来删除两个间接级别。

但是,我发现如果被迭代的项目没有实现,则第二个模式不会编译Copy

#[derive(PartialEq)]
struct Foo(i32);

fn main() {
    let a = [Foo(0), Foo(1), Foo(2)];

    // This works
    let _ = a.iter().filter(|&x| *x != Foo(1));

    // This also works
    let _ = a.iter().filter(|&x| x != &Foo(1));

    // This does not compile
    let _ = a.iter().filter(|&&x| x != Foo(1));
}
Run Code Online (Sandbox Code Playgroud)

你得到的错误是:

error[E0507]: cannot move out of a shared reference
  --> src/main.rs:14:30
   |
14 |     let _ = a.iter().filter(|&&x| x != Foo(1));
   |                              ^^-
   |                              | |
   |                              | data moved here
   |                              | move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
   |                              help: consider removing the `&`: `&x`
Run Code Online (Sandbox Code Playgroud)

这是否意味着如果我使用&&x解构模式,并且值为Copy,Rust 会默默地复制我正在迭代的每个值?如果是这样,为什么会发生这种情况?

har*_*mic 5

在 Rust 中,函数或闭包参数是无可辩驳的模式。

Rust 参考中,它说:

默认情况下,标识符模式将变量绑定到匹配值的副本或从匹配值移动,具体取决于匹配值是否实现 Copy。

所以,在这种情况下:

let _ = a.iter().filter(|&x| *x != Foo(1));
Run Code Online (Sandbox Code Playgroud)

闭包正在传递一个对正在迭代的项目的引用的引用;因此x绑定到项目引用的副本。你总是可以复制一个引用(它基本上是一个无操作)所以这总是成功的。

在这种情况下:

let _ = a.iter().filter(|&&x| x != Foo(1));
Run Code Online (Sandbox Code Playgroud)

x被绑定到项目本身的副本 - 如果项目不是,则失败Copy

参考文献还说:

这可以更改为使用 ref 关键字绑定到引用,或使用 ref mut 绑定到可变引用。

不过,在这种情况下,这不是很有用:&&ref x结果 x 是对项目的引用,就像您使用&x.