Iterator in Rust (1)

栏目: IT技术 · 发布时间: 4年前

内容简介:Iterators是迭代器,迭代器用来产生一串值。Rust提供了迭代器来遍历vectors,string,hashtables等,除此外:我们也可以创建自己的迭代器。Rust的for 循环可以使用迭代器,除此外,迭代器本身也提供很丰富的方法来使用迭代器。迭代器是弹性灵活的,表达力很强,而且效率很高。我们以下面的函数为例:

前言

Iterators是迭代器,迭代器用来产生一串值。Rust提供了迭代器来遍历vectors,string,hashtables等,除此外:

  • 产生文本中的每一行的内容

  • 到达网络服务器的每个网络连接 (connection)

  • 通过communication channel获得的来自其他线程的值

我们也可以创建自己的迭代器。Rust的for 循环可以使用迭代器,除此外,迭代器本身也提供很丰富的方法来使用迭代器。

迭代器是弹性灵活的,表达力很强,而且效率很高。我们以下面的函数为例:

fn triangle(n: i32)-> i32{
    let mut sum = 0;
    for i in 1..n+1 {
        sum += i
    }
    sum
}

给定入参n ,计算, 1+2+ …+n 的值。函数写的啰嗦。如果此处使用迭代器,因为迭代器有fold方法,可以用如下语句简洁地完成同样的功能:

fn triangle_v2(n: i32) -> i32 {
    (1..n+1).fold(0, |sum, item| sum+item)
}

Iterator and IntoIterator Traits

实现了std::iter::Iterator的任意数据结构,都可以称之为迭代器:

trait Iterator {
	type Item ;
	fn next(&mut self) -> Option<self::Item> ;
}

Item是迭代器产生的数据类型。该Trait要实现一个next method来产生出Some(v):

  • 要么产生出该迭代器的next value
  • 要么返回None,表示迭代器已经迭代到尽头,无法产生新的value

如果某种数据结构,存在一种自然的迭代方法,这表明,该数据结构实现了std::iter::IntoIterator Trait,该trait中提供了into_iter方法处理此事,即:

  • 输入是该数据结构本身
  • 输出是该数据结构对应的迭代器

最典型最容易理解的是vector。

fn main() {
    println!("There's:");
    let v = vec!["antimony", "arsenic", "aluminum", "tony"];

    for elem in &v {
        println!("{}", elem);
    }

    println!("===========================================");
    let mut iterator = (&v).into_iter();
    while let Some(element) = iterator.next(){
        println!("{}", element);
    }
    println!("Hello, world!");
}

输出如下:

There's:
antimony
arsenic
aluminum
tony
===========================================
antimony
arsenic
aluminum
tony
Hello, world!

for循环使用IntoIterator::into_inter 把 &v转成了一个迭代器,然后不断地执行 Iterator::next。当Iterator::next 返回Some(element)时,执行循环体的内容,如果Iterator::next 返回None,那么循环结束。

上面示范代码中,两种迭代的方式本质时一样的,上面方法for循环的本质就是下面的方法。

如果返回Iterator::next 返回None之后,继续调用next方法会发生什么?Iterator未定义这种行为,大部分迭代器只是会再次返回None,但也不是全部的迭代器都是如此。

创建迭代器

iter 和 iter_mut 方法

大多数的collection类型提供了iter和iter_mut方法,可以返回迭代器。切片如&[T]或者&str 也有iter和iter_mut方法。这种方法比较通用和自然的方法产生迭代器。

fn main() {
    let v = vec!["antimony", "arsenic", "aluminum", "tony"];
    let mut iterator = v.iter();
    assert_eq!(iterator.next(), Some(&"antimony"));
    assert_eq!(iterator.next(), Some(&"arsenic"));
    assert_eq!(iterator.next(), Some(&"aluminum"));
    assert_eq!(iterator.next(), Some(&"tony"));
}

std::path::Path 也实现了iter方法,每次产生一个路径部分。

use std::ffi::OsStr ;
use std::path::Path ;

fn main() {
    let path = Path::new("/etc/ceph/ceph.conf");
    let mut iterator = path.iter();

    assert_eq!(iterator.next(), Some(OsStr::new("/")));
    assert_eq!(iterator.next(), Some(OsStr::new("etc")));
    assert_eq!(iterator.next(), Some(OsStr::new("ceph")));
    assert_eq!(iterator.next(), Some(OsStr::new("ceph.conf")));
}

IntoIterator 实现

如果一个类型实现了IntoIterator,那么就可以通过调用 into_iter方法,转换成迭代器。

use std::collections::BTreeSet ;

fn main() {
    let mut favorite = BTreeSet::new();
    favorite.insert("Rust Programming".to_string());
    favorite.insert("Hello World".to_string());
    favorite.insert("ZFS internal".to_string());

    let mut it = favorite.into_iter();
    assert_eq!(it.next(), Some("Hello World".to_string()));
    assert_eq!(it.next(), Some("Rust Programming".to_string()));
    assert_eq!(it.next(), Some("ZFS internal".to_string()));
    assert_eq!(it.next(), None);
}

上面的BTreeSet类型实现了IntoIterator trait,所以可以调用into_iter方法。BTreeSet中的元素,以升序迭代,因此,顺序是:

  • Hello World
  • Rust Programming
  • ZFS internal

实际上,大部分的collections类型都实现了IntoIterator trait。

我们需要注意如下三种遍历方法:

for element in &collection {..}
for element in &mut collection {..}
for element in collection {..}

第一种是共享引用,第二种是可变引用,第三种是会consume collection,即会获得元素的所有权。

但是我们也要小心,不是所有的collection都提供三种实现,比如HashSet和BTreeSet,不支持可变引用。

drain 方法

很多collection提供了drain方法。这个方法对该类型使用可变应用 mutable reference,即执行完drain之后,原始的类型发生了变化。调用该方法后:

  • 返回一个新的迭代器
  • 原迭代器的内容发生了变化
use std::iter::FromIterator;

fn main() {
    let mut outer = "Earth".to_string();
    let inner = String::from_iter(outer.drain(1..4));

    assert_eq!(outer, "Eh");
    assert_eq!(inner, "art");

    let mut v = vec![1,2,3];
    let u: Vec<_> = v.drain(1..).collect();
    assert_eq!(v , &[1]);
    assert_eq!(u, &[2,3]);

    v.drain(..);
    assert_eq!(v, &[]);
}

##


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

让云落地

让云落地

【美】Michael J. Kavis(迈克尔 J.凯维斯) 著 / 陈志伟、辛敏 / 电子工业出版社 / 2016-3 / 65.00元

云计算落地已成事实。从前几年的概念普及,到如今越来越多的企业将业务迁移至云上,云计算正在改变整个社会的信息资源使用观念和方式。云计算还在不断成长,技术细节也在不断变化之中。对于使用者而言,能够基于自身的业务、技术和组织需求等各方面情况,选择正确的云服务模式,是成功使用云计算最关键的技术决策之一。 《让云落地:云计算服务模式(SaaS、PaaS和IaaS)设计决策》共有 16 章,作者有意避开......一起来看看 《让云落地》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具