20

关于这个例子,我有两个问题:

let a = [1, 2, 3];

assert_eq!(a.iter().find(|&&x| x == 2), Some(&2));
assert_eq!(a.iter().find(|&&x| x == 5), None);
  1. 为什么&&x在闭包参数中使用而不仅仅是x?我知道这&是传递对对象的引用,但是两次使用它是什么意思?

    我不明白文档是怎么说的:

    因为find()需要一个引用,并且许多迭代器迭代引用,这会导致参数是双重引用的可能令人困惑的情况。您可以在下面的示例中看到这种效果,使用&&x.

  2. 为什么Some(&2)使用而不是Some(2)

4

2 回答 2

26

a是类型[i32; 3]i32三个s 的数组。[i32; 3]不实现iter方法,但确实取消引用到&[i32]. &[i32]实现一个iter产生迭代器 的方法。此迭代器实现Iterator<Item=&i32>.

它使用&i32而不是i32因为迭代器必须处理任何类型的数组,并且并非所有类型都可以安全地复制。因此,它不是将自身限制为可复制类型,而是通过引用而不是值来迭代元素。

find为所有Iterators 定义的方法。它使您可以查看每个元素并返回与谓词匹配的元素。问题:如果迭代器产生不可复制的值,那么将值传递给谓词将无法从find. 该值无法重新生成,因为迭代器(通常)不可重绕或可重新启动。因此,find必须通过引用而不是按值将元素传递给谓词。

因此,如果您有一个实现 的迭代器Iterator<Item=T>,则Iterator::find需要一个接受 a&T并返回 a的谓词bool[i32]::iter生成一个实现Iterator<Item=&i32>. 因此,Iterator::find在数组迭代器上调用需要一个带有&&i32. 也就是说,它将谓词传递给指向所讨论元素的指针的指针。

因此,如果您要编写a.iter().find(|x| ..),则类型x&&i32. 这不能直接与字面值进行i32比较2。有几种方法可以解决这个问题。一种是显式取消引用x: a.iter().find(|x| **x == 2)。另一种是使用模式匹配来解构双重引用:a.iter().find(|&&x| x == 2). 在这种情况下,这两种方法完全相同。[1]

至于为什么Some(&2)使用:因为a.iter()是over的迭代器&i32而不是.的迭代器i32。如果您查看 的文档Iterator::find,您会看到 for Iterator<Item=T>,它返回一个Option<T>. 因此,在这种情况下,它返回一个Option<&i32>,所以这就是你需要比较它的。


[1]:只有在谈论非Copy类型时,差异才有意义。例如,|&&x| ..不能在 a 上工作&&String,因为您必须能够String从引用后面移出,这是不允许的。但是,|x| **x .. 起作用,因为这只是在不移动任何东西的情况下到达参考内部。

于 2017-05-07T06:05:24.330 回答
4

1)我认为这本书的解释很好,也许我.cloned()下面的例子会有用。但是由于.iter()迭代引用,您必须另外指定引用,因为find需要引用。

2).iter()正在迭代引用;因此,您可以找到参考。

.cloned()如果您不必处理引用,您可以使用它来查看它的外观:

assert_eq!(a.iter().cloned().find(|&x| x == 2), Some(2));
于 2017-05-07T05:50:23.427 回答