12.1.2 在 C# 中使用迭代器
当迭代器最初于 C# 2.0 引入时,最常见的用途是为了简化自己的集合的 IEnumerable<T> 接口的实现。在 C# 中使用的编程风格已经有了演变,现在迭代器能与其它各种数据处理操作的函数式结构一起使用。
迭代器可以用来生成任意序列。我们将从一个简单的示例开始,它生成小于 1 百万的阶乘序列,并格式化成字符串形式。清单 12.1 显示了完整的源代码。
Listing 12.1 Generating factorials using iterators (C#)
static IEnumerable<string> Factorials() {
int factorial = 1;
for(int num = 0; factorial < 1000000; num++) {
factorial = factorial * num;
yield return String.Format("{0}! = {1}", num, factorial);
}
}
C# 编译器对迭代器代码执行相当复杂的转换,创建一个"隐藏"类型,实现 IEnumerable<T> 接口。清单 12.1 有趣的地方在于如何处理局部状态。我们声明一个局部变量以保存一些可变状态,第二个可变变量声明是 for 循环的一部分。算法在一个循环内部实现,每次我们想从迭代器中取出另一个值时,它执行都会。循环体更新迭代器的局部状态,并生成新的计算值。
代码是非常命令式的,因为它严重依赖于变量,但从迭代器的外部看,几乎就像函数式的数据类型,因为,可变状态都隐藏了。让我们看看序列表达式(sequence expression),它是通常的 F# 机制,不仅可以生成序列,而且可以处理序列。