关于Rust中迭代器的个人笔记

—— 2022/9/5

一、 参考来源

std::iter 的官方文档

二、迭代器 Iterator

凡是实现了 std::iter::Iterator 这个trait的对象,都可以称为迭代器。而迭代器的一个关键方法是next()。当然,trait里还提供了一些自定义的功能,详细可查文档。

三、迭代器协议

这里提供三种常见的方法来创建迭代器。

  • iter() 它在 &T 上进行迭代

  • iter_mut() 它在 &mut T 上进行迭代

  • into_iter() 它在 T 上进行迭代

文档地址

这里的三个方法签名是迭代器协议,也就是说只要你符合使用规范,一般使用都可以进行迭代操作。

迭代器协议规范:

  • pub fn iter(&self) -------------------> Iterator ---------------> &Item;

  • pub fn iter_mut(&mut self) ------> Iterator ---------------> &mut Item;

  • pub fn into_iter(self) ---------------> Iterator ---------------> Item;

从标准库里,只定义了into_iter() 这个方法的接口—— trait IntoIterator

四、转换迭代的接口 IntoIterator

其参考文档为 IntoIterator

这个trait的含义是,当实现了这个trait的对象,其自身可通过方法into_iter(self) 转换为一个迭代器。注意,对象T的所有权会转移到这个方法里的,看方法里的是self。

五、for 循环

std::iter 的文档中提到for循环语法其实是一个迭代器的语法糖。

image.png

反糖化近似为,

image.png

六、解决 for 会转移对象所有权的解决办法

迭代器协议中 into_iter 的已经实现了,还有两个规定了不会转移所有权。那么这种在for中是怎样被解决的呢?

文档 中有提到,两种约定用法。

image.png

这里,如果我们查看 Vec 的 文档 便可以发现,Vec 的 iter() 是在左栏中的。

image.png

这说明了,其自身没有实现这个方法,但因为其实现了 trait Deref ,并返回的是 [T] 切片类型,所以其就是一个关于 [T] 切片的智能指针,同时继承了 [T] 的所有方法。

那么我们切换到 slice 的文档

同样,我们能在左栏中找到 iter() 和 iter_mut() 这两个方法。

image.png

从上图的名字我们可以得出,iter() 和 iter_mut() 是其自身实现,并没有相应的接口。故可以推出迭代器的这两项是我们自身定义的,只是约定俗成。不过为了阅读方便,最好在实现时,语义统一。

七、for 循环中关于引用类型的妙用

文档中,对于for循环怎样实现不转移所有权,介绍了一个小妙招。

image.png

对for反糖后,大概得,

image.png

在Rust中,引用也是一种类型,也可以实现 trait。故我们可以利用好这点,为类型的引用类型实现 IntoIterator。例如,

image.png

当然为了与迭代器协议的语义一致,我们要设计一个实现了 Iterator 的迭代器里面的 next 返回的是 Item 的引用。这里就可以参考 slice 里的 iter() 和 iter_mut() 的实现了。

请注意,&T 与 &mut T 是两种不同的类型。这样的区分,有利于那些规定了不能修改内容的对象,例如python的tuple类型。

八、迭代器例子

接下来,就让我们创建一个自己的迭代器。这例子是模仿 Vec 和 slice 来写的,目的是与上面约定的迭代器协议一致。

首先我们创建一个 tuple structure。

image.png

迭代的目的是使用for循环从第一个数迭代到第三个数。

迭代器协议把迭代对象和数据对象分开了,同时也分成了三种类型。

  • 第一种类型是转移所有权的方式,转换器是 into_iter(&self),
    首先创建一个IterA,用于接收类型A的实例对象。换言之,其就是在for循环内主要实现迭代功能的对象。
image.png

那么还要做一个A与IterA 的转换器。

image.png

OK,第一种类型完成。

  • 第二种是使用不可变引用,转换器是 iter(&self)。

因为iter() 方法不是trait里定义的,所以其不是一定实现。但是为了语义一致,且参考了slice里的设计,这里加进去。

接下来,如上,首先设计一个迭代器,接收的是&self类型。

image.png

然后再实现A与IterRefA的转换器。

image.png
  • 第三种是使用可变引用,转换器是iter_mut(&mut self)

其代码与第二种相近。这里省略不表。

请注意的是,可变的可以不实现,其意味着,你不想提供一种可变的方式来迭代。类似于&’static str这种,不想让用户修改其内容。故可不提供实现。

综上所述,要实现一个迭代器,一般是三个步骤。

  1. 设计数据;

  2. 包装数据;

  3. 实现转换;

九、IntoIterator与Iterato有趣关系

在上面说过,for循环是先调用对象的into_iter方法。当一个对象直接实现了Iterator,但没有自定义IntorIterator时,for循环也成功执行。这是因为,在IntoIterator里,做了一个这样的实现,

image.png

其意思是,为所有实现了Iterator的对象,同样也实现一份IntoIterator。这是一个很有趣的说明,一个Iterator对象自身也能转换为一个Iterator对象,即其自身。

开始听时有点懵圏,但对比了Python,你会发现比比皆是,这种现象。

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,928评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,748评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,282评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,065评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,101评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,855评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,521评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,414评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,931评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,053评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,191评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,873评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,529评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,074评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,188评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,491评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,173评论 2 357

推荐阅读更多精彩内容