C13 Part2 闭包和迭代器
- [13.5 迭代器:Iterator trait和next方法](#13.5 迭代器:Iterator trait和next方法)
-
- [13.5.1 迭代器的定义](#13.5.1 迭代器的定义)
- [13.5.2 Iterator trait 和 next方法](#13.5.2 Iterator trait 和 next方法)
- [13.5.3 几个迭代方法](#13.5.3 几个迭代方法)
- [13.6 迭代器:消耗和产生迭代器的方法](#13.6 迭代器:消耗和产生迭代器的方法)
-
- [13.6.1 消耗迭代器的方法](#13.6.1 消耗迭代器的方法)
- [13.6.2 产生其他迭代器的方法](#13.6.2 产生其他迭代器的方法)
- [13.7 迭代器:使用闭包捕获环境](#13.7 迭代器:使用闭包捕获环境)
- [13.8 迭代器:使用Iterator trait创建自定义迭代器](#13.8 迭代器:使用Iterator trait创建自定义迭代器)
- [13.9 使用迭代器改进代码](#13.9 使用迭代器改进代码)
- [13.10 性能比较:循环 vs 迭代器](#13.10 性能比较:循环 vs 迭代器)
13.5 迭代器:Iterator trait和next方法
13.5.1 迭代器的定义
- 迭代器模式:依次为一系列项里面的某个元素执行某些任务
- 迭代器负责:
- 遍历每个项
- 确定遍历何时完成
- Rust中的迭代器特点:
- 惰性的:需要调用消费迭代器的方法,否则迭代器本身没有任何效果
- 需要调用消耗迭代器的方法才有效
- 例子
rust
let x = vec![1,2,3];
let x_iter = x.iter();
// 到目前为止,迭代器没有使用,所以是没有任何效果
// 简单的使用示例,使用for循环进行遍历
rust
for val in x_iter {
println!("Got: {}", val);
}
13.5.2 Iterator trait 和 next方法
-
所以迭代器都实现了Iterator trait
-
Iterator trait定义于标准库,定义大致如下:

-
type Item和Self::Item定义了与此trait关联的类型
- 实现Iterator trait需要定义一个Item类型,它用于next方法的返回类型(迭代器的返回类型)
-
Iterator trait仅要求实现一个方法:next
-
next:
- 每次返回迭代器中的一项
- 返回结果包裹在Some里
- 迭代结束,返回None
-
可以直接在迭代器上调用next方法
-
例子:
注意:x_iter 是可变的
rust
#[test]
fn iterator_demo() {
let x = vec![11,222,3];
let mut x_iter = x.iter();
assert_eq!(x_iter.next(), Some(&11));
assert_eq!(x_iter.next(), Some(&222));
assert_eq!(x_iter.next(), Some(&3));
}
13.5.3 几个迭代方法
- iter方法:在不可变引用上创建迭代器
- into_iter方法:创建迭代器会获得所有权
- iter_mut方法L迭代可变的引用
13.6 迭代器:消耗和产生迭代器的方法
13.6.1 消耗迭代器的方法
- 在标准库中,Iterator trait有一些带默认实现的方法
- 其中有一些方法会调用next方法
- 实现Iterator trait时必须实现next方法
- 调用next的方法叫做"消耗型适配器"
- 因为调用它们会把迭代器耗尽
- 例子:sum方法
- 取得迭代器的所有权
- 通过反复调用next,遍历所有元素
需要指明类型 i32, let total:i32 = x_iter.sum();
rust
#[test]
fn iterator_demo() {
let x = vec![11,222,3];
let x_iter = x.iter();
// 需要指明类型
let total:i32 = x_iter.sum();
assert_eq!(total, 236);
}
13.6.2 产生其他迭代器的方法
- 定义在Iterator trait上的另外一些方法叫做"迭代器适配器"
把迭代器转换为不同种类的迭代器
- 通过链式调用使用多个迭代器适配器来执行复杂操作
- 举例:map 迭代型适配器
rust
#[test]
fn iterator_demo() {
let x = vec![11,222,3];
let x_iter = x.iter();
// map的意思是给x中每个元素都+1
// 之后再求和
let total:i32 = x_iter.map(|x| x+1).sum();
assert_eq!(total, 236+3);
}
- collect方法:消耗型适配器
rust
let x = vec![11,222,3];
let x_iter = x.iter();
// 需要显式的将collect转换为Vec<_>,但是Vec中的类型由编译器自行推断
let collection:Vec<_> = x_iter.map(|x| x+1).collect();
println!("{:?}", collection);
输出:
12, 223, 4
13.7 迭代器:使用闭包捕获环境
- 使用闭包捕获环境:
- filter方法
- 接收一个闭包
- 返回类型为bool,并且遍历迭代器的每个元素
- 当闭包返回true时:当前元素将会包含在filter产生的迭代器中
- 当闭包返回false时:当前元素不会包含在filter产生的迭代器中
shoes.into_iter()创建了一个迭代器并且获得所有权
rust
struct Shoe {
size: u32,
style: String
}
fn shoe_in_special_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
shoes.into_iter().filter(|x| x.size == shoe_size).collect()
}
13.8 迭代器:使用Iterator trait创建自定义迭代器
- 实现next方法
自定义的迭代器需要实现type Item和next方法
rust
use std::path::Iter;
// Counter本身就是一个迭代器
struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter
{
Counter { count: 0 }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 5 {
self.count += 1;
Some(self.count)
}
else {
None
}
}
}
测试:一直调用next方法,看返回结果是否符合预期
rust
#[test]
fn test_next_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);
}
第一个迭代器:1,2,3,4,5
第二个迭代器:2,3,4,5
要求两个迭代器相乘,并且里面的元素必须能够被三整除
最后求和
说明:
Counter::new().zip(Counter::new().skip(1)) 对应的应该是
Vec里面是个元组
(1,2), (2,3), (3,4), (4,5)
rust
#[test]
fn test_next_counter() {
let sum : u32 = Counter::new()
.zip(Counter::new().skip(1))
.map(|(a,b)| a*b)
.filter(|x| x %3 == 0)
.sum();
assert_eq!(sum, 0);
}
13.9 使用迭代器改进代码
- 可以替代clone,直接让Configuration获取所有权
- 可以进行长度检查和索引
rust
pub fn search_sensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
// let mut vec = Vec::new();
// for item in content.lines() {
// if item.contains(query)
// {
// vec.push(item);
// }
// }
// vec
content.lines().filter(|line| line.contains(query)).collect();
}