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 迭代器

相关推荐
洲星河ZXH2 小时前
Java,泛型
java·开发语言·windows
木木木一2 小时前
Rust学习记录--C13 Part1 闭包和迭代器
开发语言·学习·rust
Wcy30765190662 小时前
文件包含漏洞及PHP伪协议
开发语言·php
CopyProfessor2 小时前
Java Agent 入门项目模板(含代码 + 配置 + 说明)
java·开发语言
枫叶丹42 小时前
【Qt开发】Qt系统(八)-> Qt UDP Socket
c语言·开发语言·c++·qt·udp
代码游侠2 小时前
ARM 嵌入式开发学习——从内核到外设
arm开发·笔记·嵌入式硬件·学习
码农客栈2 小时前
小程序学习(十二)之命令行创建uni-app项目
学习·小程序·uni-app
爱问问题的小李2 小时前
学习面试题
学习
xiaobobo33302 小时前
STM32学习HAL库的一些知识点积累
stm32·学习·硬件软件一盘棋·寄存器操作·寄存器功能搜索