迭代器(Iterator)可以允许对序列中的每一个元素执行某个操作。
Rust 的迭代器分为三种:
-
iter()
返回一个常量引用,不可改变元素的值 -
iter_mut()
返回一个可变引用,能够修改元素的值 -
into_iter()
会拿走容器的 ownership
Iterator
Trait
迭代器实现了 Iterator
trait,定义如下(type Item
的用法在后面例子中会讲):
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// methods with default implementations elided
}
Iterator
trait 要求必须实现 next
方法,它返回一个封装在 Some
中的元素,如果没有下一个元素,则返回 None
。之所以要求必须实现 next
,是因为 Iterator
默认实现的某些其他方法会调用。
例如:
#[cfg(test)]
mod tests {
#[test]
fn iterator_demonstration() {
let v1 = vec![1, 2, 3];
let mut v1_iter = v1.iter();
assert_eq!(v1_iter.next(), Some(&1));
assert_eq!(v1_iter.next(), Some(&2));
assert_eq!(v1_iter.next(), Some(&3));
assert_eq!(v1_iter.next(), None);
}
}
值得注意的是迭代器变量定义为 mut
,因为每次调用 next
都会修改迭代器指向下一个元素。
消耗 Iterator
Iterator
trait 中调用 next
的方法称为 consuming adaptors。因为使用这些方法会“耗尽”这个迭代器,例如 sum
。由于迭代器都是惰性的,必须使用 consuming adaptors 才能得到运行结果。
#[test]
fn iterator_sum() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
let total: u32 = v1_iter.sum();
assert_eq!(total, 6);
}
此后无法再使用 v1_iter
,因为sum
已经拿走了它的 ownership。
生成 Iterator
除了消耗 Iterator 的, 也有生成 Iterator 的方法,称为 iterator adaptors。但是生成后的 Iterator 上必须使用 consuming adaptors 来得到结果。
例如,map
方法可以将旧的 iterator 映射到一个新的 iterator。下面的代码将 v1
中的每个元素加 1 并生成一个 v2
。注意,map
只是做了 iterator 的映射,并不是直接把 v1
变成 v2
。
#[test]
fn iterator_map() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
let v2_iter = v1_iter.map(|x| {x + 1});
let v2: Vec<_> = v2_iter.collect();
assert_eq!(v2, vec![2, 3, 4]);
}
还有一个常用的 iterator adapter 是 filter
方法:
#[derive(PartialEq, Debug)]
struct Shoe {
size: u32,
style: String,
}
fn shoes_in_my_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
shoes.into_iter().filter(|s| s.size == shoe_size).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn filters_by_size() {
let shoes = vec![
Shoe {
size: 10,
style: String::from("sneaker"),
},
Shoe {
size: 13,
style: String::from("sandal"),
},
Shoe {
size: 10,
style: String::from("boot"),
},
];
let in_my_size = shoes_in_my_size(shoes, 10);
assert_eq!(
in_my_size,
vec![
Shoe {
size: 10,
style: String::from("sneaker")
},
Shoe {
size: 10,
style: String::from("boot")
},
]
);
}
}
shoes_in_my_size
函数筛选出所有大小为 10 的鞋。filter
也是一个从 iterator 到 iterator 的映射。在这里,我们使用 into_iter
拿走了原来的容器的 ownership。
自定义 Iterator
我们定义了一个计数器类:
struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter {
return Counter{count: 0};
}
}
然后让它实现 Iterator
trait,计数到 5 终止:
impl Iterator for Counter {
type Item = u32; // call to next() will return Option<u32>
fn next(&mut self) -> Option<Self::Item> {
if self.count < 5 {
self.count += 1;
return Some(self.count);
}
return None; // return None when iteration ends
}
}
这里值得注意的点已经在注释中标出。测试代码如下:
#[test]
fn test_counter() {
let mut counter = Counter::new();
assert_eq!(counter.next(), Some(1));
assert_eq!(counter.next(), Some(2));
assert_eq!(counter.next(), Some(3));
assert_eq!(counter.next(), Some(4));
assert_eq!(counter.next(), Some(5));
assert_eq!(counter.next(), None);
}
网友评论