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 会默默地复制我正在迭代的每个值?如果是这样,为什么会发生这种情况?
在 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
.