Rust学习记录--C13 Part2 闭包和迭代器

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 使用迭代器改进代码

  1. 可以替代clone,直接让Configuration获取所有权
  2. 可以进行长度检查和索引
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();
}

13.10 性能比较:循环 vs 迭代器

相关推荐
SomeOtherTime4 小时前
Rust所有权(AI回答)
开发语言·后端·rust
Easyhood4 小时前
Android 开发入门实践(十四):Compose 副作用入门与四个常用 API
android·开发语言·kotlin·android jetpack·compose
白杨尚青5 小时前
C++进阶篇(六):map 和 set 的模拟实现——用红黑树封装 mymap/myset(迭代器 + operator[])
开发语言·c++·迭代器·stl·set·map·红黑树
饮水桶_T8 小时前
JAVA IO流笔记
开发语言·数据结构·算法
Felven11 小时前
C. Brr Brrr Patapim
c语言·开发语言
li星野11 小时前
相位补偿学习记录:把被颅骨“打乱“的声波重新对齐
学习
Z21-X12 小时前
云原生运维学习笔记:ECShop全链路容器化部署与Docker底层资源隔离深度剖析
运维·笔记·学习·云原生
路溪非溪12 小时前
python标准库使用总结
开发语言·python
red_redemption13 小时前
自由学习记录(230)
学习
SomeOtherTime14 小时前
Rust 面向对象介绍(AI回答)
开发语言·python·rust