迭代协议(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
倒数 0MoveNext 先走一步再报告,所以首个产出是 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日
