跟着谷歌安卓团队学习Rust-强大的迭代器(Iterators)

跟着谷歌安卓团队学习Rust-强大的迭代器(Iterators)

大家好,我是梦兽编程。欢迎回来与梦兽编程一起刷Rust的系列。

这是由 Google 的 Android开发团队的分享Rust课程。本课程涵盖了 Rust 的方方面面,从基本语法到泛型和错误处理等高级主题。

该课程的最新版本可以在 google.github.io/comprehensi...

如果你喜欢看梦兽编程的版本可以订阅跟着谷歌安卓团队学Rust订阅最新内容,梦兽编程也期待大家关注我的个人网站。

加入梦兽编程微信群,公众号回复111即可加入交流群与梦兽进行交流。

迭代器

在之前的分享中,我们都知道Rust 是一种系统编程语言,它的设计重点是内存安全和性能。在编码中迭代器是一个非常重要的概念,它提供了一种简洁高效的方式来遍历集合。

Rust的迭代器强大就强大在编译阶段就知道你的操作是否超出集合异常! 今日让我们一起来学习Rust的迭代器吧

我们先看一个代码

rust 复制代码
struct Fibonacci {
    curr: u32,
    next: u32,
}

impl Iterator for Fibonacci {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        let new_next = self.curr + self.next;
        self.curr = self.next;
        self.next = new_next;
        Some(self.curr)
    }
}

fn main() {
    let fib = Fibonacci { curr: 0, next: 1 };
    for (i, n) in fib.enumerate().take(5) {
        println!("fib({i}): {n}");
    }
}

在这个例子中我们可以看到迭代器是 Rust 中一种抽象数据类型(ADT),它提供了一种遍历集合的接口(Iterator)并且实现next的方法。

也就是说Rust标准库中许多类型都实现了迭代器特质,你也可以自行实现它。只要你实现了Iterator,你同样可以使用forwhile这些方式进行遍历的迭代器,不够一般不会这么做,都是使用函数组合进行操作,方便数据流的链式操作。

例如Vec、&Vec和&[T]都实现了它,所以你可以用for i in some_vec { .. }遍历向量。 但是,some_vec.next()这个方法是不存在的,因为IntoIterator才是真正提供迭代器功能的特质。如果有需要你要先执行 iter 让 Vec 变成迭代器后进行操作。

javascript 复制代码
fn main() {
    let vec = vec![1, 2, 3, 4, 5];
    // 创建向量迭代器
    let mut iter = vec.iter();
    // 遍历向量元素
    while let Some(val) = iter.next() {
        println!("{}", val);
    }
}

迭代器的组合

如果你是一个函数范式爱好者,那么你肯定使用过链式操作。如 map、filter、for_each、reduce 等,以便于创建更复杂的遍历逻辑。

Rust的迭代器同样支持这种的用法。举个例子:

rust 复制代码
fn main() {
    let vec = vec![1, 2, 3, 4, 5];
    // 使用 map 函数将每个元素乘以 2
    let mut new_vec = vec.iter().map(|x| *x * 2).collect::<Vec<_>>();
    // 使用 for_each 函数打印新向量的元素
    new_vec.iter().for_each(|x| println!("{}", x));
}

更多api可查阅(rustwiki.org/zh-CN/core/...%255Bhttps%3A%2F%2Frustwiki.org%2Fzh-CN%2Fcore%2Fiter%2Ftrait.Iterator.html%255D%25E6%259C%2589%25E5%25A4%259A%25E5%25B9%25B4%25E5%2585%25B6%25E4%25BB%2596%25E8%25AF%25AD%25E8%25A8%2580%25E5%25BC%2580%25E5%258F%2591%25E7%25BB%258F%25E9%25AA%258C%25E7%259C%258B%25E7%259D%2580%25E8%25BF%2599%25E4%25BA%259B%25E5%2587%25BD%25E6%2595%25B0%25E9%2583%25BD%25E6%2598%25AF%25E8%2580%2581%25E7%2586%259F%25E4%25BA%25BA%25E3%2580%2582 "https://rustwiki.org/zh-CN/core/iter/trait.Iterator.html)%5Bhttps://rustwiki.org/zh-CN/core/iter/trait.Iterator.html%5D%E6%9C%89%E5%A4%9A%E5%B9%B4%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91%E7%BB%8F%E9%AA%8C%E7%9C%8B%E7%9D%80%E8%BF%99%E4%BA%9B%E5%87%BD%E6%95%B0%E9%83%BD%E6%98%AF%E8%80%81%E7%86%9F%E4%BA%BA%E3%80%82")

IntoIterator

我们刚刚有说过Vec它原本是不支持next的方法,我们可以通过iter把集合转换成迭代器。

如果现在我有有一个新的结构体也需要支持这种特效,我们要怎么做呢?

先上代码

rust 复制代码
struct Grid {
    x_coords: Vec<u32>,
    y_coords: Vec<u32>,
}

impl IntoIterator for Grid {
    type Item = (u32, u32);
    type IntoIter = GridIter;
    fn into_iter(self) -> GridIter {
        GridIter { grid: self, i: 0, j: 0 }
    }
}

struct GridIter {
    grid: Grid,
    i: usize,
    j: usize,
}

impl Iterator for GridIter {
    type Item = (u32, u32);

    fn next(&mut self) -> Option<(u32, u32)> {
        if self.i >= self.grid.x_coords.len() {
            self.i = 0;
            self.j += 1;
            if self.j >= self.grid.y_coords.len() {
                return None;
            }
        }
        let res = Some((self.grid.x_coords[self.i], self.grid.y_coords[self.j]));
        self.i += 1;
        res
    }
}

fn main() {
    let grid = Grid { x_coords: vec![3, 5, 7, 9], y_coords: vec![10, 20, 30, 40] };
    for (x, y) in grid {
        println!("point = {x}, {y}");
    }
}

我们主要看Grid结构体的实现,它实现了IntoIterator并且实现了into_iter,巧妙的将本来不支持 iter 的 x_coords 属性和 y_coords 。在执行 into_iter() 后获取GridIter对象让它进行next的遍历操作。

在rust的约束中,你可以省去不必要的迭代器方法执行,除非你想分开两行写。

scss 复制代码
// 只要你实现了两个接口,rust知道这是迭代器,默认你想遍历这个结合
for (x, y) in grid {
    println!("point = {x}, {y}");
}

FromIterator

在上面的例子中,我可以看到我们每次执行完迭代器,想让迭代器转换回数组集合时都做一个操作。

rust 复制代码
// 使用 map 函数将每个元素乘以 2
    let mut new_vec = vec.iter().map(|x| *x * 2).collect::<Vec<_>>();

collect方法就是让迭代器转换回一个数组集合的操作,它实现了FromIterator接口。这个特性通常用于将迭代器的元素收集到一个集合中,比如向量(Vec)、哈希表(HashMap)等。

rust 复制代码
// 一个样本集合,这只是 Vec<T> 的包装
#[derive(Debug)]
struct MyCollection(Vec<i32>);

// 让我们给它一些方法,以便我们可以创建一个方法并向其中添加一些东西。
impl MyCollection {
    fn new() -> MyCollection {
        MyCollection(Vec::new())
    }

    fn add(&mut self, elem: i32) {
        self.0.push(elem);
    }
}

// 我们将实现 FromIterator
impl FromIterator<i32> for MyCollection {
    fn from_iter<I: IntoIterator<Item=i32>>(iter: I) -> Self {
        let mut c = MyCollection::new();

        for i in iter {
            c.add(i);
        }

        c
    }
}

// 现在我们可以创建一个新的迭代器...
let iter = (0..5).into_iter();

// ... 并用它制作一个 MyCollection
let c = MyCollection::from_iter(iter);

assert_eq!(c.0, vec![0, 1, 2, 3, 4]);

// 也收集作品!

let iter = (0..5).into_iter();
let c: MyCollection = iter.collect();

assert_eq!(c.0, vec![0, 1, 2, 3, 4]);

FromIterator 特性定义了一个 from_iter 方法,该方法接受一个实现了 IntoIterator 特性的对象作为参数,并返回一个实现了 FromIterator 特性的集合。这个方法可以用于创建任何类型的集合,只要该类型实现了 FromIterator 特性。

文章持续更新,可以微信搜【梦兽编程】阅读,本文 rexweb.link 已收录,欢迎 Star 催更。

本文使用 markdown.com.cn 排版

相关推荐
往日情怀酿做酒 V176392963820 分钟前
Django基础之路由
后端·python·django
桃园码工39 分钟前
第三章:基本语法 2.变量和常量 --Go 语言轻松入门
后端·golang·go语言
lix的小鱼2 小时前
scala之全文单词统计
java·开发语言·后端·python·算法·c#·scala
liuxin334455662 小时前
欢迪迈手机商城:基于SpringBoot的用户体验提升
spring boot·后端·ux
梦想画家2 小时前
Rust eyre 错误处理实战教程
后端·rust·错误处理
怀旧6662 小时前
Java LinkedList 讲解
java·开发语言·后端·个人开发
爱读源码的大都督2 小时前
PostgreSQL数据库中Sequence的使用详解
数据库·后端·架构
一直要努力哦3 小时前
Spring源码的分析之启动流程
java·后端·spring
2402_857589363 小时前
SpringBoot框架助力欢迪迈手机商城的国际化
spring boot·后端·智能手机