跟着谷歌安卓团队学习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 排版

相关推荐
他日若遂凌云志2 小时前
深入剖析 Fantasy 框架的消息设计与序列化机制:协同架构下的高效转换与场景适配
后端
快手技术2 小时前
快手Klear-Reasoner登顶8B模型榜首,GPPO算法双效强化稳定性与探索能力!
后端
二闹2 小时前
三个注解,到底该用哪一个?别再傻傻分不清了!
后端
用户49055816081252 小时前
当控制面更新一条 ACL 规则时,如何更新给数据面
后端
林太白2 小时前
Nuxt.js搭建一个官网如何简单
前端·javascript·后端
码事漫谈2 小时前
VS Code 终端完全指南
后端
该用户已不存在3 小时前
OpenJDK、Temurin、GraalVM...到底该装哪个?
java·后端
怀刃3 小时前
内存监控对应解决方案
后端
码事漫谈3 小时前
VS Code Copilot 内联聊天与提示词技巧指南
后端
Moonbit3 小时前
MoonBit Perals Vol.06: MoonBit 与 LLVM 共舞 (上):编译前端实现
后端·算法·编程语言