迭代器和生成器
在没有迭代器之前,做遍历操作,是非常麻烦的。
以 C 语言为例,遍历数组:
for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
{
printf("%d\n", arr[i]);
}
遍历链表:
PNODE p = pHead->pNext;
while (p)
{
printf("%d\n", p->data);
p = p->pNext;
}
上面的遍历方式存在两个问题:
- 对于不同的数据容器,需要实现不同的遍历方式
- 需要手动维护遍历索引,容易出错
后来的新生代语言,比如 Python,JavaScript,都引入了迭代器,来解决这个问题。
以 JavaScript 为例,遍历数组:
for (const item of arr) {
console.log(item);
}
遍历字符串:
for (const char of str) {
console.log(char);
}
遍历文件内容:
for (const line of fs.readFileSync('file.txt', 'utf8')) {
console.log(line);
}
可以看到,对于不同的数据容器,都可以使用统一的遍历方式。
这要得益于「迭代协议」的功劳,就像 HTTP 协议一样,标准了请求和响应的格式。
迭代协议又包含了「可迭代协议」和「迭代器协议」。
在 JavaScript 中,符合「可迭代协议」的数据结构,必须实现 [Symbol.iterator]()
方法。
[Symbol.iterator]()
是一个零入参的函数,返回一个符合「迭代器协议」的对象。
符合「迭代器协议」的对象,必须实现 next()
方法。
next
方法是一个零入参的函数,返回一个包含 value
和 done
属性的对象。