前言
说到迭代器,在学习C++时一般只是使用auto iterator来遍历一个容器,当时也就只把他当做一个通用指针。深入一点可能探讨了一下迭代器失效原理之类的,但对这个东西其实一直是一种抽象的感官,今天就借着红宝书来细细品读一下这个东西。
1.理解迭代:
首先看一段红宝书原话:
迭代的英文“iteration”源自拉丁文itero,意思是“重复”或“再来”。在软件开发领域,“迭代”的意思是按照顺序反复多次执行一段程序,通常会有明确的终止条件。
循环是迭代机制的基础,这是因为它可以指定迭代的次数,以及每次迭代要执行什么操作。每次循环都会在下一次迭代开始之前完成,而每次迭代的顺序都是实现定义好的。
上述内容可能很抽象,但如果把迭代换成一个词理解就很简单了。“遍历”这个词大家很熟悉,毕竟一接触编程我们做过遍历数组。那如果我们把“迭代”直接换成“多次遍历”来理解上段话,看是否符合以上定义。
首先“多次”肯定就满足了上述反复执行,从上文指定迭代的次数也可以看出迭代是有一定次数的。再者,如果要实现遍历,你要遍及每一个元素肯定就需要一定的顺序,不然就会导致有的读了多次,有的没读。所以遍历也就满足了上述的 每次迭代的顺序都是实现定义好的。其三,遍历的元素肯定是有限的,所以也满足通常会有明确的终止条件。
但是把迭代直接当成多次遍历其实也不妥,有的迭代方式不一定要访问所有元素呀。所以多次遍历只是迭代的一个子集。说成多次遍历是因为大多数时候我们说做迭代也是指做遍历。如果要准确地描述迭代,我们可以理解成重复多次地按照一定顺序访问元素。
2.为什么要引入迭代器以及抽象意义上的迭代器
比如我们要迭代数组,或者说遍历一个数组,我们需要知道两件事:1.按照什么顺序依次访问。 2.如何对一个元素进行访问。 数组很好办到,索引从0到数组长度-1依次访问,并且通过[index]就可以实现访问。但这不是一种通用的方法,因为并不是所有数据结构都具有顺序,也不是所有数据结构都能用索引下标访问。所以需要一个通用的工具来实现迭代。这个工具不仅封装了对数据结构的进行遍历的功能,并且他是通用的,提供了统一的使用接口,这样不同的使用者不用区分这是哪个数据结构的工具。这里所说的工具就是迭代器。其实这也就是红宝书中7.2迭代器模式所提及的:这种概念上的分离正是iterable和iterator的强大之处。现在你不用为写方法遍历发愁了,我写好了一个专门的通用工具给你,只要你使用这个工具的一个接口就可以迭代了,虽然不同的数据结构我为你提供的工具不同,但提供的工具都有这个接口,只要用这个接口就行了,你也不用为了适配不同的数据结构还要去写不同的方法了。
3.可迭代对象:
还是看一段红宝书的原话:
实现iterable接口要求同时具备两种能力:支持迭代的自我识别能力和创建实现Iterator接口的对象的能力。在ECMAScript中,这意味着必须暴露一个属性作为“默认迭代器”,而且这个属性必须使用特殊的Symbol.iterator作为键。这个默认迭代器属性必须引用一个迭代器工厂函数,调用这个工厂函数必须返回一个新迭代器。
这句话看完你可能有点懵,没事,我给你翻译一下:也就是说,你要让你的对象是可迭代对象,那么你必须给你的对象添加一个[Symbol.iterator]属性,属性值是工厂函数,工厂函数负责返回一个迭代器。所以可迭代对象就是 1.实现了迭代器功能的对象,也就是上文所说的支持迭代的自我识别能力,迭代器不就有这个能力吗。2.实现了创建迭代器对象的功能,具体通过给[Symbol.iterator]属性添加一个工厂函数创建,这个工厂函数进行创建。也就是上文的创建实现Iterator接口的对象的能力。
4.迭代器
这里直接通过红宝书的例子来带你具体看看什么是迭代器,并且也具体化解释了上文的可迭代对象。
class Counter {
constructor(limit) {
this.count = 1;
this.limit = limt;
}
next() {
if (this.count <= this.limit) {
return { done: false, value: this.count++ };
} else {
return { done: true, value: undefined };
}
}
[symbol.iterator]() {
return this;
}
}
前文说过:必须给你的对象添加一个[Symbol.iterator]属性,属性值是工厂函数,工厂函数负责返回一个迭代器。我们看例子中的[symbol.iterator]属性,返回的是本身,也就是说本身就是一个迭代器。也就是我们所说的迭代工具,而迭代工具要满足提供一个封装好的迭代接口,就是上面的next接口。
ps:这篇文章只是为了琳琳才写
MySQL的binlog相信大家都有所耳闻,但是可能没有真正日常使用过。 因此,本文结...
一、GIF图 二、前台代码 // 调用方法 hotlineLine(); // 定时刷新 setInterval(f...
目录中出现 jsconfig.json 文件表明该目录是 JavaScript 项目的根目录。 Json 文...
为什么我们需要它 不得不说,在知道这个命令的时,以及之后的使用中,我都超级热...
本文转载自微信公众号「三太子敖丙」,作者三太子敖丙。转载本文请联系三太子敖...
端点路由(Endpoint Routing)最早出现在ASP.NET Core2.2,在ASP.NET Core3.0提升...
详解JSP中使用过滤器进行内容编码的解决办法 问题 当通过JSP页面,向数据库中插...
通过ImageMagickObject的identify获取图片的信息,在命令行下好用,但是放到程序...
前言 静态文件(如 HTML、CSS、图像和 JavaScript)等是Web程序的重要组成部分。...
博主最近在做一个个人的博客网站,准备用 thymeleaf 实现一个动态加载一二级文章...