Skip to content

循环和迭代 ​

  • 循环: 是指在满足指定的条件的情况下, 重复的执行一段代码(需要满足指定条件才停止)
  • 迭代: 是指对一个序列中的元素逐个访问的过程(元素全部被消费后会自动停止)

迭代器 ​

迭代器模式: 对一系列项目执行某些任务 迭代器就负责遍历每一个项

Rust 的迭代器: Rust 迭代器是惰性的, 除非显示调用, 否则迭代器本身没有任何作用

rust
fn main() {
    let nums = vec![3, 2, 1];
    let mut iter = nums.iter();
    println!("iter: {:?}", iter); // 获取一个迭代器对象

    // 手动一次次迭代
    let item1 = iter.next();      // 手动调用 next 方法
    println!("item1: {:?}", item1); // Some(3)

    let item2 = iter.next();
    println!("item2: {:?}", item2); // Some(2)

    let item3 = iter.next();
    println!("item3: {:?}", item3); // Some(1)

    let item4 = iter.next();
    println!("item3: {:?}", item4); // None


    // 一次性全部遍历
    for item in nums.iter() {
        println!("item is: {:?}", item);
        // 依次输出: 3 2 1
    }
}
rust
pub fn first_char_uppercase(input: &str) -> String {
    // 假设传入的是 "rust"
    // 那么 "rust".chars() 会返回 -> Chars(["r", "u", "s", "t"])
    // 在迭代器执行一次 next 后:
    // 1.匹配到的字符是: "r"
    // 2.其他还没有被消费的是: Chars(["u", "s", "t"])
    // 3.所以这个match语句会走到 Some
    //    3.1 匹配到 Some("r") -> "r".to_uppercase() -> "R"
    //    3.2 Chars(["u", "s", "t"]) -> as_str() -> "ust"
    //    3.3 最终 format!("{R}{ust}") 返回新的字符串 "Rust"
    let mut chars = input.chars();
    match chars.next() {
        None => String::new(),
        Some(first) => format!("{}{}", first.to_uppercase(), chars.as_str()),
    }
}

fn main() {
    let str = first_char_uppercase("rust");
    assert_eq!(str, "Rust");
}

Iterator trait 和 next ​

所有迭代器都实现了 Iterator 特性, iterator trait 定义于标准库

rust
pub trait Iterator {
    // 先不用管这个语法是什么意思,
    // 只需要知道, 这个是 next 方法的返回值类型
    type Item;

    fn next(&mut self) -> Option<Self::Item>;

    // ... 迭代器的其他方法 ... //
}

消费迭代器的方法 ​

在 Iterator 中实现了很多方法, 其中在这些方法内部调用 next 方法的 就叫做 消费适配器(consuming adaptors)

被迭代器迭代的元素会有限的, 被消费已给就相当于吃掉了一个

rust
fn main () {
    let items = vec![1, 2, 3, 4, 5];

    let iter = items.iter();

    let x: i32 = iter.sum(); // 会获取迭代器的所有权
    println!("sum = {}", x);

    // 无法再次使用 迭代器, 因为所有权在 sum 方法那里
    // for item in iter {
    //     println!("item = {}", item);
    // }

    // 这样是可以的, 因为这样是新创建了一个迭代器
    // 和原来那个迭代器(iter) 没有关系
    for item in items.iter() {
        println!("item = {}", item);
    }
}

迭代器适配器 ​

所谓迭代器适配器(Iterator adaptors), 就是指可以将当前迭代器变为不同类型的迭代器, 可以链式调用多个迭代器, 但是 最后必须调用一个消费适配器方法 才能开始迭代, 因为所有的迭代器都是惰性的

rust
fn main () {
    let items = vec![1, 2, 3, 4, 5];

    let iter  = items.iter();
    println!("    iter: {:?}", iter);

    let map_iter = iter.map(|x| x + 1);

    // 可以看到 map_iter 并不是原来的 iter
    // 而且,他仅仅是返回了一个新的迭代器
    // 并没有执行出结果
    println!("map_iter: {:?}", map_iter);

    // 如果需要看到效果, 需要调用一个 消费适配器
    // 如果不调用
    let map_items: Vec<i32> = map_iter.collect();

    // 输出: [2, 3, 4, 5, 6]
    println!("map_items: {:?}", map_items);
}

自定义迭代器 ​

要自定义迭代器就必须实现 std::iter::Iterator 这个 trait

rust
#[derive(Debug)]
struct Stack<T> {
    items: Vec<T>,
}

impl<T> Stack<T> {
    pub fn new() -> Self {
        Self { items: Vec::new() }
    }
    pub fn push(&mut self, item: T) {
        self.items.push(item);
    }
    pub fn pop(&mut self) -> T {
        self.items.pop().unwrap()
    }

    pub fn iter(&self) -> impl Iterator<Item = &T> {
        // 注意: 返回的是 Vec 类型的 Iter
        // 而不是后续手动实现的 Iter
        self.items.iter()
    }

    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
        self.items.iter_mut()
    }

    pub fn iter_into(self) -> impl Iterator<Item = T> {
        self.items.into_iter()
    }
}

impl<T> Iterator for Stack<T> {
    type Item = T;

    // 只需要实现 next 方法即可
    fn next(&mut self) -> Option<Self::Item> {
        self.items.pop()
    }
}

fn main() {
    let mut stk = Stack::new();

    stk.push(1);
    stk.push(2);
    stk.push(3);

    // 使用自定义迭代器遍历
    for item in stk {
        println!("item: {}", item); // 3,2,1
    }

    // 使用 Vec Iterator 遍历, 元素不会从 Stack 中弹出
    let mut stk2 = Stack::new();
    stk2.push(1);
    stk2.push(2);
    stk2.push(3);
    for item in stk2.iter() {
        println!("item: {}", item); // 3,2,1
    }
}

使用自定义迭代器上的其他方法 ​

rust
fn main () {
    let mut stk = Stack::new();

    stk.push(1);
    stk.push(2);
    stk.push(3);

    // items 需要指定类型
    let items: Vec<i32> = stk.map(|x| x + 1).collect();

    // 4,3,2
    println!("{:?}", items);
}

迭代器和闭包的性能 ​

迭代器是 Rust 的 零成本抽象(zero-cost abstractions)之一, 它意味着抽象并不会引入运行时开销

简单点来说就是: 虽然源码是这样写的, 但是最后还是会编译为循环, 所以不用担心性能问题

闭包和迭代器是 Rust 受函数式编程语言观念所启发的功能, 他们对 Rust 以底层的性能来明确的表达高级概念的能力有很大贡献, 闭包和迭代器的实现达到了不影响运行时性能的程度, 这正是 Rust 竭力提供零成本抽象的目标的一部分

这句话是Rust程序设计语言上的

Released under the MIT License.