生成器 (计算机编程)

2025-05-24 05:15:27

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 GetEven(IEnumerable numbers) {

foreach (int i in numbers) {

if ((i % 2) == 0) {

yield return i;

}

}

}

可以使用多个yield return语句:

public class CityCollection : IEnumerable {

public IEnumerator GetEnumerator() {

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].