与「**生成器 (计算机编程)**」標題相近或相同的条目页，請見「**生成器**」。
**生成器**（Generator），是计算机科学中特殊的子程序。实际上，所有生成器都是迭代器。生成器非常类似于返回数组的函数，都是具有参数、可被调用、产生一系列的值。但是生成器不是构造出数组包含所有的值并一次性返回，而是每次产生一个值，因此生成器看起来像函数，但行为像迭代器。 

生成器可以用更有表达力的控制流结构实现，如协程或头等續體。生成器，也被称作半协程（semicoroutine），是特殊的、能力更弱的协程，总是在传回一个值时把控制交还给调用者，而不是像协程那样指出另一个协程继续执行。

使用
--

生成器通常在一个循环内部被调用。 生成器第一次被调用是在进入这个循环结构时，创建一个对象以封装生成器的状态、绑定的实参。生成器的实体接着被执行直至遇到一个特别的`yield`动作，在这里提供给`yield`动作的值被返回给调用者。在下一次调用同一个生成器的时候，生成器从`yield`动作之后恢复执行，直到遇上另一个`yield`动作。生成器的执行也可以遇到`finish`动作而终止。

由于生成器在需要的才计算它的要被`yield`的值，因此可以用来代表一个串流，这种序列要一次性全部计算出来是昂贵的甚至是不可能的，这种情况还包括无穷序列或现场数据串流。 

如果需要及早求值（主要是在序列是有限的时候，否则求值将永不终止），可以使用列表或使用并行结构来创建一个列表替代生成器。例如，Python的一个生成器`g`，通过`l = list(g)`，可被求值成列表`l`。而在F#中，序列表达式`seq { ... }`，将除了`[ ... ]`之外的惰性的（生成器或序列）求值为及早的（列表）。

在有生成器出现的情况下，语言的循环构造，比如`for`和`while`，可以归约成一个单一的`loop ... end loop`构造；可以用合适的生成器以正确的方式，顺畅的模拟所有常见的循环构造。例如，一个按范围的循环如`for x = 1 to 10`，可以通过生成器而被实现为迭代，比如Python的`for x in range(1, 10)`。进一步的，`break`可以被实现为向生成器发送`finish`，而接着在循环中使用`continue`。

历史
--

生成器最早出现于CLU语言（1975年），也是字符串操纵语言Icon（1977年）的显著特征。它现在出现在Python、C#、Ruby、最新版本的ECMAScript（ES6/ES2015）与其他语言之中。在CLU与C#中，生成器称作迭代器，在Ruby称作枚举器。

语言实例
----

### CLU

CLU使用`yield`语句来在用户定义数据抽象上进行迭代：

```
string\_chars = iter (s: string) yields (char);
  index: int := 1;
  limit: int := string$size (s);
  while index <= limit do
    yield (string$fetch(s, index));
    index := index + 1;
    end;
end string\_chars;

for c: char in string\_chars(s) do
   ...
end;

```

### Icon

在Icon中，所有表达式（包括循环）都是生成器。语言有很多内建生成器，甚至使用生成器机制实现某些逻辑语义（逻辑析取或`OR`以此达成）。

打印从`0`到`20`的平方，可以如下这样使用协程完成：

```
   local squares, j
   squares := create (seq(0) ^ 2)
   every j := |@squares do
      if j <= 20 then
         write(j)
      else
         break

```

但是多数时候，定制生成器是使用`suspend`关键字来实现，它的功能完全类似CLU中的`yield`关键字。

### C++

使用宏预处理的例子见:

```
$generator(descent)
{
 // place for all variables used in the generator
 int i; // our counter

 // place the constructor of our generator, e.g. 
 // descent(int minv, int maxv) {...}
 
 // from $emit to $stop is a body of our generator:
 
 $emit(int) // will emit int values. Start of body of the generator.
 for (i = 10; i > 0; --i)
 $yield(i); // a.k.a. yield in Python,
 // returns next number in [1..10], reversed.
 $stop; // stop, end of sequence. End of body of the generator.
};

```

可迭代：

```
int main(int argc, char\* argv[])
{
 descent gen;
 for(int n; gen(n);) // "get next" generator invocation
 printf("next number is %d\n", n);
 return 0;
}

```

C++11提供的foreach loop可用于任何具有`begin`与`end`成员函数的类。还需要有`operator!=`, `operator++` 与`operator*`。例如：

```
#include <iostream>
int main()
{
 for (int i: range(10))
 {
 std::cout << i << std::endl;
 }
 return 0;
}

```

一个基本实现：

```
class range
{
private:
 int last;
 int iter;

public:
 range(int end):
 last(end),
 iter(0)
 {}

 // Iterable functions
 const range& begin() const { return \*this; }
 const range& end() const { return \*this; }

 // Iterator functions
 bool operator!=(const range&) const { return iter < last; }
 void operator++() { ++iter; }
 int operator\*() const { return iter; }
};

```

### C#

C# 2.0开始可以利用`yield`构造生成器。

```
// Method that takes an iterable input (possibly an array)
// and returns all even numbers.
public static IEnumerable<int> GetEven(IEnumerable<int> numbers) {
 foreach (int i in numbers) {
 if ((i % 2) == 0) {
 yield return i;
 }
 }
}

```

可以使用多个`yield return`语句： 

```
public class CityCollection : IEnumerable<string> {
 public IEnumerator<string> GetEnumerator() {
 yield return "New York";
 yield return "Paris";
 yield return "London";
 }
}

```

### Python

Python自2001年的2.2版开始支持生成器。下面是生成器一个例子，它是个计数器：

```
def countfrom(n):
    while True:
        yield n
        n += 1

# 例子使用: 打印出从10到20的整数
# 注意这个迭代通常会终止，尽管 
# countfrom()被写为了无限循环

for i in countfrom(10):
    if i <= 20:
        print(i)
    else:
        break

```

另一个生成器例子，它按需要无尽的产生素数：

```
import itertools
def primes():
    yield 2
    n = 3
    p = []
    while True:
        # 这有效于Python 2.5+ 
        if not any(n % f == 0 for f in 
                     itertools.takewhile(lambda f: f\*f <= n, p)): 
            yield n
            p.append(n)
        n += 2

```

Python的生成器可以认为是一个迭代器包含了冻结的栈帧。当用`next()`方法调用迭代器，Python恢复冻结的栈帧，继续执行至下一次的`yield`语句。生成器的栈帧再一次冻结，被yield的值返回给调用者。 

PEP 380 (Python 3.3开始)增加了`yield from`表达式，允许生成器将它的一部份操作委托给另一个生成器。

#### 生成器表达式

Python拥有建模于列表推导式的一种语法，叫做生成器表达式，用来辅助生成器的创建。下面的例子扩展了上面第一个例子，使用生成器表达式来计算来自`countfrom`生成器函数的数的平方：

```
squares = ( n\*n  for n in countfrom(2) )

for j in squares:
    if j <= 20:
        print(j)
    else:
        break

```

### Smalltalk

下面例子使用Pharo Smalltalk，黄金分割率生成器对`goldenRatio next`调用，每次返回一个更加逼近的黄金分割率： 

```
goldenRatio := Generator on: [ :g |
    | x y z r | 
	x := 0.
	y := 1.
	[  
		z := x + y.
		r := (z / y) asFloat.
		x := y.
		y := z.
		g yield: r
	] repeat	
].

goldenRatio next.

```

下面的表达式返回的下次`10`个逼近。

```
(1 to: 10) collect: [ :dummy | goldenRatio next].

```

参见
--

* 列表推导式
* 迭代器
* Iteratee（英语：）
* 惰性求值
* Corecursion（英语：）
* 协程
* 續體

参考文献
----

* Stephan Murer, Stephen Omohundro, David Stoutamire and Clemens Szyperski: Iteration abstraction in Sather. *ACM Transactions on Programming Languages and Systems*, 18(1):1-15 (1996)  （页面存档备份，存于）

|  |  |  |
| --- | --- | --- |
| 

|  |  |
| --- | --- |
| 规范控制 編輯維基數據鏈接 | 
* BNF: cb122247630 (data)
* GND: 4129040-9
* J9U: 987007562694505171
* LCCN: sh85053846

 |

 |