跳到主要内容

迭代器和生成器

在没有迭代器之前,做遍历操作,是非常麻烦的。

以 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;
}

上面的遍历方式存在两个问题:

  1. 对于不同的数据容器,需要实现不同的遍历方式
  2. 需要手动维护遍历索引,容易出错

后来的新生代语言,比如 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 协议一样,标准了请求和响应的格式。

迭代协议又包含了「可迭代协议」和「迭代器协议」。

Iteration Protocol

在 JavaScript 中,符合「可迭代协议」的数据结构,必须实现 [Symbol.iterator]() 方法。

[Symbol.iterator]() 是一个零入参的函数,返回一个符合「迭代器协议」的对象。

符合「迭代器协议」的对象,必须实现 next() 方法。

next 方法是一个零入参的函数,返回一个包含 valuedone 属性的对象。

Reference