为 Iterator::find 提供闭包时的值和引用

Value and references when providing a closure to Iterator::find

我在学习Rust方面还有很长的路要走,但我发现值和引用的使用方式不一致。这可能是我对语言的无知造成的。

例如,这个有效:

let x = (1..100).find(|a| a % 2 == 0);

let x = (1..100).find(|a| a > 50); 没有。我不确定 - 为什么?

使用 let x = (1..100).find(|&a| a > 50); 修复了错误,但后来我认为使用 &a 就像要求引用范围中的元素,因此以下应该有效,但它不起作用:

let x = (1..100).find(|&a| *a > 50);

还是不知道为什么!

非平凡模式通常 解构 某些东西,即,将某些东西分解成它的组件。这通常反映了一些 construction 语法,所以它看起来非常相似但实际上是相反的。这种二元论适用于记录、元组、框(一旦正确实现),也适用于引用:

  • 表达式 &x 创建对 x 求值结果的引用。这里,&T 类型的值转换为 &T.
  • 类型的值
  • 另一方面,模式&a消除了引用,因此a绑定到后面 引用(注意 a 也可以是另一个更复杂的模式)。此处,&&T 值变为 T 值。

你的例子中的闭包都是&i32 -> bool1类型。因此它们接受对整数的引用,并且您可以使用该引用(您在第一个示例中这样做,因为算术运算符也为引用重载)或者您可以使用模式 &a。在后一种情况下,a 是一个 i32(比较上面的一般解释,用 i32 代替 T),所以你当然不能进一步取消引用它。

1 这实际上不是真正的类型,但它足够接近我们的目的。

but then I thought using &a is like asking for reference of element from the range

是你推理的错误部分。在 pattern 中使用 & 恰恰相反 - 它隐式地取消引用匹配的值:

let &a = &10;
// a is 10, not &10 or &&10

你可能已经知道,find()接受一个满足FnMut(&T) -> bool的闭包,也就是说,这个闭包接受迭代器的每个元素的引用,所以如果你写(1..100).find(|a| ...), a 将是 &i32.

类型

let x = (1..100).find(|a| a % 2 == 0) 起作用是因为算术运算符被重载以处理引用,因此您可以将 % 应用于引用并且它仍然能够编译。

比较运算符未重载以处理引用,因此您需要从 &i32 获取 i32。这可以通过两种方式完成,首先,就像您已经做过的那样:

let x = (1..100).find(|&a| a > 50)

这里我们使用 & 模式来隐式取消引用函数参数。相当于这个:

let x = (1..100).find(|a| { let a = *a; a > 50 })

另一种方法是显式取消引用参数:

let x = (1..100).find(|a| *a > 50)

I thought using &a is like asking for reference of element from the range

有时&用作运算符,有时用作模式匹配。对于闭包参数 (|&a|),它被用作模式匹配。这意味着变量 a 将在使用时自动取消引用。也相当于do

let x = (1..100).find(|a| *a > 50);