RUST 每日一省:迭代器1

Iterator

        迭代器指的是任何实现 std::iter::Iterator trait的值。这个Iterator trait的定义如下:

trait Iterator {

    type Item;

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

    ... // 其他默认方法

}

        Item 是迭代器产生值的类型。我们只需要实现一个方法——next() , 它返回一个Option<Item>。 一般情况返回Some(Item) ; 如果迭代完成,就返回None。Iterate trait中包含了很多默认的方法,不需要我们自己去实现。

 

IntoIterator

        如果有其他类型,也想迭代怎么办,只需要实现std::iter::IntoIterator就可以了。它的 into_iter 方法接收一个值,然后基于这个值返回一个迭代器:

trait IntoIterator where Self::IntoIter::Item == Self::Item { 
    type Item;
    type IntoIter: Iterator; 

    fn into_iter(self) -> Self::IntoIter;

}

        IntoIter 是迭代器值本身的类型,而 Item 是它产生值的类型。我们称任何实现 IntoIterator 的类型为可迭代类型(iterable),因为可以在需要的时候通过循环来访问它。

 

迭代器的使用

我们可以直接在迭代器上调用next方法。

fn iterator_demonstration() {

    let v1 = vec![1, 2, 3];

    let mut iter = v1.iter();

    assert_eq!(iter.next(), Some(&1));

    assert_eq!(iter.next(), Some(&2));

    assert_eq!(iter.next(), Some(&3));

    assert_eq!(iter.next(), None);

}

        我们可以手工直接调用迭代器的next() 方法,然后使用while let语法来做循环。

fn main() {

    let v = vec![1,2,3,4,5]; 
    let mut iter = v.iter();

    while let Some(i) = iter.next() { 
        println!("{}", i);

    } 
}

        这两个例子中的iter必须是可变的,因为调用next方法改变了迭代器内部用来记录序列位置的状态。换句话说,这段代码消耗或使用了迭代器,每次调用next都吃掉了迭代器中的一个元素。

        实际上, Rust里面更简洁、 更自然地使用迭代器的方式是使用for循环。 本质上来说, for循环就是专门为迭代器设计的一个语法糖。 for循环可以对针对数组切片、 字符串、Range、 Vec、 LinkedList、 HashMap、 BTreeMap等所有具有迭代器的类型执行循环, 而且还允许我们针对自定义类型实现循环.

use std::collections::HashMap; fn main() {

    let v = vec![1,2,3,4,5,6,7,8,9];

    for i in v {

        println!("{}", i); 

    } 

    let map : HashMap<i32, char> =

    [(1, 'a'), (2, 'b'), (3, 'c')].iter().cloned().collect();

    for (k, v) in &map {

        println!("{} : {}", k, v);

    } 

}

        在for循环中我们之所以不要求变量v可变,是因为循环取得了v的所有权并在内部使得它可变了;map又可以使用&。那么for循环是怎么做到这一点的呢? 原因就是 IntoIterator 这个trait

        只要某个类型实现了IntoIterator, 那么调用into_iter() 方法就可以得到对应的迭代器。 这个into_iter() 方法的receiver是self, 而不是&self, 执行的是move语义。 这么做,可以同时支持Item类型为T、 &T或者&mut T, 用户有选择的权力。

// container在循环之后生命周期就结束了,循环过程中的每个item是从container中move出来的

    for item in container {}

// 迭代器中只包含container的&型引用,循环过程中的每个item都是container中元素的借用

    for item in &container {}

// 迭代器中包含container的&mut型引用,循环过程中的每个item都是指向container中元素的可变借用

    for item in &mut container {}

        Rust的for<item>in<container>{<body>}语法结构就是一个语法糖。 这个语法的原理其实就是调用<container>.into_iter() 方法来获得迭代器, 然后不断循环调用迭代器的next() 方法, 将返回值解包,赋值给<item>, 然后调用<body>语句块。

        Rust的IntoIterator trait实际上就是for语法的扩展接口。 如果我们需要让各种自定义容器也能在for循环中使用, 那就可以借鉴标准库中的写法, 自行实现这个trait即可。

相关推荐

  1. RUST 每日1

    2024-03-13 11:06:05       43 阅读
  2. ·模式

    2024-03-13 11:06:05       48 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-13 11:06:05       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-13 11:06:05       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-13 11:06:05       87 阅读
  4. Python语言-面向对象

    2024-03-13 11:06:05       96 阅读

热门阅读

  1. 【Rust日报】Ascent:在 Rust 中嵌入的逻辑编程语言

    2024-03-13 11:06:05       38 阅读
  2. Linux中一些基础命令

    2024-03-13 11:06:05       46 阅读
  3. 自动点名器

    2024-03-13 11:06:05       41 阅读
  4. CSS学习小结

    2024-03-13 11:06:05       37 阅读
  5. 中间件MQ面试题之Rabbitmq

    2024-03-13 11:06:05       32 阅读
  6. wsl-oracle 安装 omlutils

    2024-03-13 11:06:05       35 阅读
  7. C# List使用详解

    2024-03-13 11:06:05       44 阅读