今天看 C# 发现这样一种用法:class IntManager
{
int[] arr = { 0, 1, 2, 3 };
public IEnumerator GetEnumerator()
{
for (int i = 0; i<4; i++)
{
yield return arr[i];
}
}
}是的……对我这样孤陋寡闻的人来说,这就是这么神奇……居然可以这样写出迭代器!而且根据一些资料来看,这个迭代器是随用随取的,也就是说如果资源不在内存上,那就可以需要多少取多少,不会一次性全部取回来,非常方便。以前我只知道 yield 用在 coroutine 上。不过把这两个一结合,我就发现了神奇的现象……Tcl 的 yield 其实也不过是这样而已。proc y {} {
set i 0
while 1 {
yield [incr i]
}
}
coroutine coro y ;; -> 1,这里会调用一次 y 所以是 1
coro ;; -> 2
coro ;; -> 3
coro ;; -> 4没错,这还是一个……嗯,我们不如来研究一些好玩的。proc fibo {} {
;# 第一次 yield 之前可以尝试做一些初始化工作
yield ;# 然后用 yield 返回结果,这里自然是不需要的
set a 0
set b 1
while 1 {
;# a,b = b,a+b
set t $b
set b [expr $a+$t]
set a $t
yield $a
}
}
coroutine next fibo
next ;; -> 1
next ;; -> 1
next ;; -> 2
-> 就是 1,1,2,3,5,8,13,21,34,55,...实际上用这个求这个数列的效率不高,因为求过一次数据就丢弃了,不如以前写过的一个缓存版本快。但是这个版本不会爆栈(相比递归版本),因为根本只有一个栈帧和循环版的效率理论上来说差不多,没测试。