Iterator
Iter和for循环
Rust中调用迭代器的接口就是Iterator,通常情况之下看到的for循环 就是这种迭代器的语法糖。
这种for循环使用into_iter()
在T上迭代。
1 2 3 4
| trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; }
|
- 通常情况之下,使用for循环会消耗这个集合,因为使用了
into_iter()
方法,但是实际上可以使用其他方法,如:
1 2 3 4 5 6 7 8
| let mut values = vec![41]; for x in values.iter_mut() { *x += 1; } for x in values.iter() { assert_eq!(*x, 42); } assert_eq!(values.len(), 1);
|
或者下面的:
1 2 3 4 5 6 7 8
| let mut values = vec![41]; for x in &mut values { *x += 1; } for x in &values { assert_eq!(*x, 42); } assert_eq!(values.len(), 1);
|
二者相同,因为如果集合类型 C 提供 iter(),则它通常还为 &C 实现 IntoIterator,而该实现只是调用 iter()。 同样,提供 iter_mut() 的集合 C 通常通过委派给 iter_mut() 来为 &mut C 实现 IntoIterator。
Adapters
- 接受Iterator并且返回另外一个Iterator的函数叫做迭代器适配器。常见的方法有map、take、filter。
- map()
map通常是是实现一个闭包,这个闭包是FnMut
(实例可以重复调用,并且可以改变值)类型的,它的作用是:
将一种A元素转换为想要的B元素。
map()和for循环比较像,但是如果已经使用了其他类型的迭代器,最好使用map();而在使用某种循环的副作用,使用for
1 2 3 4 5 6 7 8
| let a = [1, 2, 3];
let mut iter = a.iter().map(|x| 2 * x);
assert_eq!(iter.next(), Some(2)); assert_eq!(iter.next(), Some(4)); assert_eq!(iter.next(), Some(6)); assert_eq!(iter.next(), None);
|
关于副作用(这段代码不会运行 )
1 2 3 4 5 6 7 8 9
| (0..5).map(|x| println!("{}", x));
for x in 0..5 { println!("{}", x); }
|
过滤值,同样是创建一个闭包(这个闭包会获取引用)
1 2 3 4 5
| let a = [0i32, 1, 2]; let mut iter = a.iter().filter(|x| x.is_positive()); assert_eq!(iter.next(), Some(&1)); assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), None);
|
在使用过程中会遇到多个迭代器使用的时候,这个时候需要双引用,这个时候filter就需要进行改进:
1 2 3 4 5 6
| let a = [0, 1, 2];
let mut iter = a.iter().filter(|x| **x > 1);
assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), None);
|
可以使用解构去掉一个
1 2 3 4 5 6
| let a = [0, 1, 2];
let mut iter = a.iter().filter(|&x| *x > 1);
assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), None);
|
或者两个
1 2 3 4 5 6
| let a = [0, 1, 2];
let mut iter = a.iter().filter(|&&x| x > 1);
assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), None);
|
take创建一个迭代器,在迭代过程之中提前结束
1 2 3 4 5 6 7
| let a = [1, 2, 3];
let mut iter = a.iter().take(2);
assert_eq!(iter.next(), Some(&1)); assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), None);
|
take() 通常与无限迭代器一起使用,以使其成为有限的:
1 2 3 4 5 6
| let mut iter = (0..).take(3);
assert_eq!(iter.next(), Some(0)); assert_eq!(iter.next(), Some(1)); assert_eq!(iter.next(), Some(2)); assert_eq!(iter.next(), None);
|
如果少于 n 个元素可用,take 会将自身限制为底层迭代器的大小:
1 2 3 4 5
| let v = vec![1, 2]; let mut iter = v.into_iter().take(5); assert_eq!(iter.next(), Some(1)); assert_eq!(iter.next(), Some(2)); assert_eq!(iter.next(), None);
|
enumerate会创建一个迭代器,这个迭代器给出当前的迭代次数以及下一个值,返回的迭代器索引是(i,val),i为当前索引,val是迭代器返回的值。
1 2 3 4 5 6 7 8
| let a = ['a', 'b', 'c'];
let mut iter = a.iter().enumerate();
assert_eq!(iter.next(), Some((0, &'a'))); assert_eq!(iter.next(), Some((1, &'b'))); assert_eq!(iter.next(), Some((2, &'c'))); assert_eq!(iter.next(), None);
|
zip会将两个迭代器压缩为单个迭代器,这个迭代器是成对的。
如果其中一个迭代器返回None,则整个迭代器返回None
1 2 3 4 5 6 7 8 9
| let a1 = [1, 2, 3]; let a2 = [4, 5, 6];
let mut iter = a1.iter().zip(a2.iter());
assert_eq!(iter.next(), Some((&1, &4))); assert_eq!(iter.next(), Some((&2, &5))); assert_eq!(iter.next(), Some((&3, &6))); assert_eq!(iter.next(), None);
|
collect会将可迭代的东西收集成为一个集合,基本方法是使用iter,最后使用collect
1 2 3 4 5 6 7
| let a = [1, 2, 3];
let doubled: Vec<i32> = a.iter() .map(|&x| x * 2) .collect();
assert_eq!(vec![2, 4, 6], doubled);
|
请注意,我们需要在左侧使用 : Vec。这是因为我们可以代替收集到例如 VecDeque 中:
1 2 3 4 5 6 7 8 9
| use std::collections::VecDeque;
let a = [1, 2, 3];
let doubled: VecDeque<i32> = a.iter().map(|&x| x * 2).collect();
assert_eq!(2, doubled[0]); assert_eq!(4, doubled[1]); assert_eq!(6, doubled[2]);
|
使用 ‘turbofish’ 而不是注解 doubled:
1 2 3 4 5
| let a = [1, 2, 3];
let doubled = a.iter().map(|x| x * 2).collect::<Vec<i32>>();
assert_eq!(vec![2, 4, 6], doubled);
|
因为 collect() 只关心您要收集的内容,所以您仍然可以将局部类型提示 _ 与 turbfish 一起使用:
1 2 3 4 5
| let a = [1, 2, 3];
let doubled = a.iter().map(|x| x * 2).collect::<Vec<_>>();
assert_eq!(vec![2, 4, 6], doubled);
|
使用 collect() 生成 String:
1 2 3 4 5 6 7 8
| let chars = ['g', 'd', 'k', 'k', 'n'];
let hello: String = chars.iter() .map(|&x| x as u8) .map(|x| (x + 1) as char) .collect();
assert_eq!("hello", hello);
|
如果您有 Result<T, E>,您可以使用 collect() 来查看它们是否失败:
1 2 3 4 5 6 7 8 9 10 11 12 13
| let results = [Ok(1), Err("nope"), Ok(3), Err("bad")];
let result: Result<Vec<_>, &str> = results.iter().cloned().collect();
assert_eq!(Err("nope"), result);
let results = [Ok(1), Ok(3)];
let result: Result<Vec<_>, &str> = results.iter().cloned().collect();
assert_eq!(Ok(vec![1, 3]), result);
|
迭代器的惰性
通常情况之下迭代器如果作用的结果是副作用的时候,尽量使用for,因为编译器会警告,并且这不会运行。
1 2 3 4 5 6 7 8 9
| let v = vec![1, 2, 3, 4, 5];
v.iter().for_each(|x| println!("{}", x));
for x in &v { println!("{}", x); }
|
Infinity
开放式迭代器是无限迭代器。
可以使用take方法更改。
1 2 3 4 5 6 7
| let numbers = 0..; let five_numbers = numbers.take(5);
for number in five_numbers { println!("{}", number); }
|
迭代器的三种形式
- iter():在&T上迭代
iter_mut():在&mut上迭代
into_iter():在T上迭代
更多内容可以查看std::iter