见识过迭代器的一众用法后,是时候针对某些使用过程中的陷阱进行特别说明了。它们或多或少都与迭代器的特性有所关联。
迭代器以及迭代器适配器都是惰性的。这意味着仅仅创建一个迭代器并不会做太多事情。在实际调用 next 之前什么都不会真正发生。如果只是为了某些“无关痛痒”的操作而创建迭代器,那么程序的反应可能让人困惑不解。例如 map 方法的例子:
let v = vec![1, 2, 3, 4, 5];
v.iter().map(|x| println!("{x}"));
这段代码不会打印任何值,因为我们只创建了一个迭代器却不使用它。编译器会针对这种行为发出警告:
warning: unused result that must be used: iterators are lazy and
do nothing unless consumed
更好的写法是使用 for 循环或调用 for_each 方法:
let v = vec![1, 2, 3, 4, 5];
v.iter().for_each(|x| println!("{x}"));
// 或者
for x in &v {
println!("{x}");
}
迭代器的元素不一定是有限的。例如,一个无上限的区间就是一个无限迭代器:
let numbers = 0..;
通常使用 take 迭代器适配器将无限迭代器转换为有限迭代器:
let numbers = 0..;
let five_numbers = numbers.take(5);
for number in five_numbers {
println!("{number}");
}
反过来的话,前面提到的 cycle 方法能将有限迭代器转换为无限迭代器。
要注意:即使那些在数学上可以在有限时间内确定结果的方法,在无限迭代器上也可能永远不会终止。具体来说,像
min这样的方法,在一般情况下需要遍历迭代器中的每个元素,对于任何无限迭代器很可能就无法成功返回。let ones = std::iter::repeat(1); let least = ones.min().unwrap(); // `ones.min()` 导致无限进行遍历 // 所以下面的语句永远不会到达: println!("The smallest number one is {least}.");