Rust 语言的迭代器有这么一个方法 std::iter::iterator::size_hint()
方法,它的返回值对于大部分人来说真的是一个迷。
首先,我们看看 官方给的解释
Returns the bounds on the remaining length of the iterator.
Specifically, size_hint() returns a tuple where the first element is the lower bound, and the second element is the upper bound.
The second half of the tuple that is returned is an Option<usize>. A None here means that either there is no known upper bound, or the upper bound is larger than usize.
翻译成中文就是
size_hint()
返回当前迭代器未迭代元素数量的上下界。具体来说,
size_hint()
返回的是元组,元组的第一个元素是未迭代元素数量的下界,第二个元素是未迭代元素的上界。
size_hint()
返回的元素的第二个元素的值是一个Option<usize>
,原因是上界有可能是不可预测的。如果上界不可预知,那么就会返回None
,如果上界的值大于usize
所能表示的最大的值,返回的也是None
。
相信官方已经说的很清楚了,也很好理解了。
但实际上有些行为是有点奇怪的。
比如
let a = [1, 2, 3]; let iter = a.iter(); assert_eq!((3, Some(3)), iter.size_hint());
数组 [1, 2, 3]
的长度是已知的,由于未开始迭代,所以上界和下界都是 3
,这就是 (3, Some(3)
的由来。
但是,请看下面的代码
// 过滤出 0..10 中的偶数.则 iter 的内容应该是(0, 2, 4, 6, 8) let iter = (0..10).filter(|x| x % 2 == 0); assert_eq!((0, Some(10)), iter.size_hint());
如果按照上面的值,这里应该是 (0,some(5))
才对,但是返回的结果竟然是 (0,some(10))
,为什么呢?
原因就是:size_hint() 未迭代数量的上界在创建迭代器之前就计算好了。它并不会发生任何迭代器求值行为。
回忆一下,我们实现一个迭代器接口的时候是不是只要实现 next()
方法,而且大家都知道,迭代器是不能重复调用的。因此,对未迭代元素的上界判定只能是迭代器创建时就界定好了。
另一个原因,迭代器是惰性求值的,所有产生迭代器的方法都是惰性求值的。
因此 filter()
方法并不会一次性把所有元素都过滤好,然后生成一个迭代器,而是要每次调用 next()
方法时才会去判断条件,这也是如果要取得 filter()
方法的所有元素,必须 filter().collect()
的原因才能得到完整的过滤列表的原因。