Skip to Content

迭代协议(Iterator)

for-in 建立在 Iterator<T> 协议之上:任何实现它的类型都能被遍历。列表、集合、映射、数组、范围、字符串全都接在这一个协议上。

协议形状

Iterator<T> 由 std::Collections 声明:

protocol Iterator<T> { func MoveNext() -> bool; func Current() -> T; func GetIterator() -> Iterator<T>; func Contains(item: T) -> bool; }

for-in 的机器是:每轮先调 MoveNext(),返回 true 就用 Current() 取值进入循环体,返回 false 结束。GetIterator() 每次遍历时被调用,用来拿一个游标。Contains 挂在协议上是为了让 in 成员判断与遍历共用一个契约。

协议名在类型注解位需要 import Collections.*; 激活裸名,或直接用 Collections.Iterator<T>。

自定义迭代

实现四个成员,自己的类型就能接进 for-in:

import Collections.*; class Countdown impl Iterator<int> { var n: int = 0; init(from: int) { n = from; } public func MoveNext() -> bool { n -= 1; return n >= 0; } public func Current() -> int => n; public func GetIterator() -> Iterator<int> => self; public func Contains(item: int) -> bool => item >= 0 && item <= n; } val c = new Countdown(3); print(c.Contains(2)); for x in c { print("倒数", x); }
True 倒数 2 倒数 1 倒数 0

MoveNext 先走一步再报告,所以首个产出是 2。这个例子的 GetIterator 返回 self,意味着游标就是自己。

游标独立

对同一个列表嵌套两层 for-in,两层互不干扰:

val xs = new list<int>(); xs.Add(1); xs.Add(2); for x in xs { for y in xs { print(x, y); } }
1 1 1 2 2 1 2 2

标准容器的每次遍历都会获得独立的游标对象,内层走完不影响外层的进度。自己实现容器时照此办理:GetIterator() 返回一个新的游标对象,不要返回 self,除非你的类型本来就是一次性迭代器。

注意

  • for-in 的迭代变量位是模式位,元组列表可以直接解构(for (n, s) in xs;list.Zip 与 map.Entries() 同)。
  • 映射遍历产出值,数组产出元素,字符串按字形簇产出字符,见 Unicode 与字形簇。
  • x in coll 成员判断走协议的 Contains 成员:列表与数组是 O(n) 线性扫,集合走 hash 判等,热点路径自己选数据结构。
最后更新于 2026年10月10日