生成器 (计算机编程)
CLU
编辑
CLU使用yield语句来在用户定义数据抽象上进行迭代[8]:
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++
编辑
使用宏预处理的例子见[9]:
$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
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
foreach (int i in numbers) {
if ((i % 2) == 0) {
yield return i;
}
}
}
可以使用多个yield return语句:
public class CityCollection : IEnumerable
public IEnumerator
yield return "New York";
yield return "Paris";
yield return "London";
}
}
Python
编辑
Python自2001年的2.2版开始支持生成器[6]。下面是生成器一个例子,它是个计数器:
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:
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表达式,允许生成器将它的一部份操作委托给另一个生成器。[10]
生成器表达式
编辑
Python拥有建模于列表推导式的一种语法,叫做生成器表达式,用来辅助生成器的创建。下面的例子扩展了上面第一个例子,使用生成器表达式来计算来自countfrom生成器函数的数的平方:
squares = (n*n for n in countfrom(2))
for j in squares:
if j <= 20:
print(j)
else:
break
ECMAScript
编辑
ECMAScript 6介入了函数生成器。
使用函数生成器书写一个无穷斐波那契序列:
function* fibonacci(limit) {
let [prev, curr] = [0, 1];
while (!limit || curr <= limit) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
// 加上限10为边界
for (const n of fibonacci(10)) {
console.log(n);
}
// 没有上界的生成器
for (const n of fibonacci()) {
console.log(n);
if (n > 10000) break;
}
// 手动迭代
let fibGen = fibonacci();
console.log(fibGen.next().value); // 1
console.log(fibGen.next().value); // 1
console.log(fibGen.next().value); // 2
console.log(fibGen.next().value); // 3
console.log(fibGen.next().value); // 5
console.log(fibGen.next().value); // 8
// 从停止的地方继续
for (const n of fibGen) {
console.log(n);
if (n > 10000) 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].