17. 迭代器模式(Iterator)

问题:想统一遍历不同数据结构,不暴露内部实现。

核心:提供 next() 方法,依次返回元素直到结束。

class NumberIterator implements Iterator<number> {
  #data: number[];
  #index: number = 0;

  constructor(data: number[]) { this.#data = data; }

  next(): IteratorResult<number> {
    if (this.#index < this.#data.length) {
      return { value: this.#data[this.#index++], done: false };
    }
    return { value: undefined, done: true };
  }
}

const iter = new NumberIterator([10, 20, 30]);
while (true) {
  const result = iter.next();
  if (result.done) break;
  console.log(result.value);
}
// 10 → 20 → 30
package iterator

import "fmt"

type Iterator[T any] struct {
  data   []T
  cursor int
}

func NewIterator[T any](data []T) *Iterator[T] {
  return &Iterator[T]{data: data}
}

func (it *Iterator[T]) Next() (T, bool) {
  var zero T
  if it.cursor >= len(it.data) {
    return zero, false
  }
  val := it.data[it.cursor]
  it.cursor++
  return val, true
}

// 使用
// iter := NewIterator([]int{10, 20, 30})
// for {
//   val, ok := iter.Next()
//   if !ok { break }
//   fmt.Println(val)
// }

实战场景

  • 数组、Map、Set 遍历:调用方不关心内部结构,只按统一协议逐个取值。
  • 分页 API:后端数据按页返回时,迭代器可以隐藏 page token 和下一页请求逻辑。
  • 数据库游标:大量数据不能一次性加载到内存,用 cursor 每次取一批或一条。
  • 文件流读取:逐行读取日志、CSV、NDJSON,比一次性读完整文件更省内存。
  • 树结构遍历:菜单、组织架构、AST 可以提供深度优先或广度优先迭代器。
  • 生成器流水线:数据清洗、过滤、转换一步步 yield,适合处理大列表或无限序列。
  • UI 虚拟列表:只迭代当前可见范围的数据,避免渲染所有节点。
  • 消息消费:队列消费者不断取下一条消息,直到被停止或没有更多消息。
  • 搜索结果聚合:从多个来源按统一迭代接口取结果,再合并、去重、排序。
  • 测试用例生成:参数组合很多时,用迭代器按需生成用例,不提前构造巨大数组。