关于示例here,我有两个问题。
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)
?
答案 0 :(得分:7)
a
的类型为[i32; 3]
;三个i32
的数组。
[i32; 3]
未实现iter
方法,但 取消引用&[i32]
。
生成迭代器的&[i32]
implements an iter
method。
This iterator实施Iterator<Item=&i32>
。
它使用&i32
而不是i32
,因为迭代器必须处理任何类型的数组,并非所有类型都可以安全地复制。因此,它不是将自己限制为可复制类型,而是通过引用而不是值来迭代元素。
Iterator
定义的 find
is a method。它允许您查看每个元素并返回与谓词匹配的元素。问题:如果迭代器产生不可复制的值,那么将值传递给谓词将导致无法从find
返回它。无法重新生成该值,因为迭代器(通常)不可重绕或可重新启动。因此,find
必须将元素传递给谓词by-reference而不是by-value。
因此,如果您有一个实现Iterator<Item=T>
的迭代器,那么Iterator::find
需要一个带&T
的谓词并返回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()
是&i32
上的迭代器,不是 i32
的迭代器。如果您查看Iterator::find
的文档,您会看到Iterator<Item=T>
的文档会返回Option<T>
。因此,在这种情况下,它会返回Option<&i32>
,因此您需要将其与之进行比较。
[1]:差异只在你谈论非Copy
类型时才有意义。例如,|&&x| ..
无法在&&String
上运行,因为您必须能够从引用后面移出String
,这是不允许的。但是,|x| **x ..
会工作,因为它只是在没有移动任何内容的情况下到达引用内部。