概念
迭代器用来遍历序列中的每一项,它也决定了什么时候结束迭代。
迭代器是惰性的,因此迭代器的使用分为两步:创建和消费
示例:
let v1 = vec![1, 2, 3];
// 获取迭代器
let v1_iter = v1.iter();
// 使用for循环消费迭代器
for val in v1_iter {
println!("Got: {}", val);
}
迭代器实现了Iterator
这一**trait**
,trait
的定义如下:
pub trait Iterator {
// 定义一个关联类型
type Item;
// 定义next的实现
fn next(&mut self) -> Option<Self::Item>;
// 此处省略了方法的默认实现
}
实现了Iterator trait
的struct
就可以成为一个迭代器
获取迭代器
获取迭代器的方式
v.iter()
v.iter_mut()
v.into_iter()
内部元素的类型
以Vector<**T**>
来说:
- 获取引用
**&T**
v.iter()
(&v).into_iter()
- 获取可变引用
**&mut T**
v.iter_mut()
(&mut v).into_iter()
- 获取所有权
**T**
v.into_iter()
下面显式调用三种获取迭代器的方法, 可以观察获取到的元素类型
for 循环自动调用 into_iter()
在为v
使用for
循环时,会为v
自动调用into_iter()
方法获取迭代器,因此可以在v
前加&
、& mut
或直接v
,以此获取变量的引用、可变引用、所有权
示例:
let mut vec = vec!(1,2,3);
// 值被移动
// 自动调用 v.into_iter()
for x in v {
println!("x = {}", x);
}
-----------------------------
// 自动调用 (&v).into_iter()
for x in &v {
println!("x = {}", x);
}
// 等价于
for x in v.iter() {
println!("x = {}", x);
}
------------------------------
// 自动调用 (&mut v).into_iter()
for x in &mut v {
println!("x = {}", x);
}
// 等价于
for x in v.iter_mut() {
println!("x = {}", x);
}
为自定义类型实现 into_iter()
struct CountdownIterator(i32);
impl Iterator for CountdownIterator {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
self.0 -= 1;
if self.0 < 0 {
None
} else {
Some(self.0)
}
}
}
struct Countdown(i32);
impl IntoIterator for Countdown {
type Item = i32;
type IntoIter = CountdownIterator;
fn into_iter(self) -> Self::IntoIter {
CountdownIterator(self.0)
}
}
impl<'a> IntoIterator for &'a Countdown {
type Item = i32;
type IntoIter = CountdownIterator;
fn into_iter(self) -> Self::IntoIter {
CountdownIterator(self.0)
}
}
impl<'a> IntoIterator for &'a mut Countdown {
type Item = i32;
type IntoIter = CountdownIterator;
fn into_iter(self) -> Self::IntoIter {
CountdownIterator(self.0)
}
}
fn main() {
let c = Countdown(10);
for i in &c {
for j in &c {
println!("({0}, {1})", i, j)
}
}
}
Vector的迭代器实现
iter()、iter_mut()方法
是结构体的自有方法
定义:
pub fn iter(&self) -> Iter<'_, T> {
Iter::new(self)
}
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut::new(self)
}
**Iter**
来自Struct std::slice::Iter
**IterMut**
来自Struct std::slice::IterMut
即Vector
使用了**slice**
中定义的迭代器
into_iter()方法
实现了**IntoIterato trait**
中的**into_iter()**
方法
定义:
pub trait IntoIterator {
type Item;
type IntoIter: Iterator;
fn into_iter(self) -> Self::IntoIter;
}
有三个实现:
// 获取借用
impl<'a, T, A> IntoIterator for &'a mut Vec<T, A> where
A: Allocator,
// 获取可变借用
impl<'a, T, A> IntoIterator for &'a Vec<T, A> where
A: Allocator,
// 获取所有权
impl<T, A> IntoIterator for Vec<T, A>
消费适配器(consuming adaptors)
Iterator trait
中存在一些有默认实现的其他方法,它们的实现中调用了next()
方法(也就是对迭代器进行消费),这些方法被称为消费适配器(consuming adaptors)
使用sum
消费适配器的示例:
fn iterator_sum() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.into_iter();
// 调用sum会获取v1_iter的所有权,因此后面不可再使用v1_iter
let sum: i32 = v1_iter.sum();
assert_eq!(sum, 6);
}
迭代器适配器(iterator adaptors)
Iterator trait
中还有一类迭代器适配器(iterator adaptors)
方法,这些方法将前一个迭代器转换为另一个迭代器,因此迭代器适配器可以链式调用。
示例:
fn iterator_adaptors() {
let v1 = vec![1, 2, 3, 4];
// 调用map对迭代器进行转换
// collect方法属于env::args,用于消费迭代器返回一个新vector
let v1_new_vec: Vec<i32> = v1.iter().map(|x| x + 2).collect();
assert_eq!(v1_new_vec, vec![3, 4, 5, 6]);
}
综合使用:自定义迭代器实现
描述:
- 创建迭代器的结构体定义
- 为结构体实现
**new**
函数,返回结构体实例 - 为结构体实现
**Iterator trait**
,重写**next**
方法 - 测试
- 调用
**zip**
方法。返回一个由2-元组组成的新迭代器,元组中的两个元素分别来自两个迭代器,下面示例的zip
方法中:- 第一个迭代器中为
1,2,3,4,5
- 第二个迭代器中为
2,3,4,5
- 结果为
(1,2),(2,3),(3,4),(4,5)
,第五对值:(5,None)
实际上从未产生过
- 第一个迭代器中为
- 调用
map
方法后,结果为2,6,12,20
- 调用
filter
方法后,结果为6,12
- 计算
sum
后,结果为18
- 调用
示例:
// 迭代器定义
struct CounterIterator {
count: u32,
}
impl CounterIterator {
fn new() -> CounterIterator {
CounterIterator { count: 0 }
}
}
// 实现Iterator trait并重写next方法的实现
impl Iterator for CounterIterator {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
if self.count < 6 {
Some(self.count)
} else {
None
}
}
}
#[test]
fn coustom_iterator_trait() {
let iter = CounterIterator::new();
// 连续调用迭代器消费器
let sum: u32 = iter
.zip(CounterIterator::new().skip(1))
.map(|(a, b)| a * b)
.filter(|x| x % 3 == 0)
.sum();
assert_eq!(sum, 18);
}
迭代器的可变引用
消耗迭代器所有权
如果在迭代器上调用参数为**self**
的消费器, 例如下面的take
方法, 这个迭代器会被消耗, 之后无法使用fn [take](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take)(**self**, n: [usize](https://doc.rust-lang.org/std/primitive.usize.html)) -> [Take](https://doc.rust-lang.org/std/iter/struct.Take.html)<Self>
take
方法拿走原迭代器的前**n**
个元素, 返回新迭代器
这里的返回值Take
是迭代器类型, 也就说调用take
方法返回了一个新的迭代器:
获取迭代器的可变引用
所以可以先拿到迭代器的可变引用, 这样的话即使调用参数为**self**
的消费器, 效果也相当于**&mut self**
这个方法是fn [by_ref](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.by_ref)(&mut self) -> [&mut](https://doc.rust-lang.org/std/primitive.reference.html)Self
by_ref
方法借用一个迭代器, 而不是消费它
可变引用也实现了迭代器
原因是有个一揽子泛型实现: 它为迭代器的可变引用实现了Iterator trait
:
可以看到里面有两次解引用操作, 以next
为例, 它要获取参数的可变引用&mut self
, 而此时的self类型是已经是可变引用类型&mut I
, 所以next
拿到的类型是**&mut &mut self**
, 所以需要两次解引用操作, 经过take
方法也是一样, 因为take
直接返回的类型就是参数类型