在Perl中没有像Python那样原生的生成器,但可以通过闭包、在词法变量中追踪状态以及生成器函数来实现惰性计算和迭代器:
sub counter { my $x = shift; return sub { return $x++; }; } my $it = counter(5); print $it->(), ", ", $it->(); # 5, 6
对于复杂的迭代器,通常使用CPAN模块 (Iterator::Simple, List::Gen)。经典的惰性模式是返回保存状态的匿名子程序。
缺点:没有内置的yield支持,许多CPAN模块缺少组合性。递归也受到栈大小的限制。
在Perl中,是否可以实现无限惰性Fibonacci数列而不导致内存溢出?
答案:是的,通过闭包:
sub fibonacci { my ($a, $b) = (0, 1); return sub { ($a, $b) = ($b, $a+$b); return $a; }; } my $fib = fibonacci(); print $fib->(), ", ", $fib->(), ", ", $fib->();
但如果将结果放入数组中,它会随着时间的推移耗尽内存(即实际上“惰性”的只有生成器本身)。
故事
在一个项目中编写了自定义的迭代器来遍历一个巨大文件,这个迭代器通过对象内部的数组实现。迭代器将整个文件加载到内存中——当文件增长时,服务在处理多个实例时开始出现OOM。
故事
用于报告细节序列的闭包生成器导致意外的内存泄漏——闭包中意外地保持了对大数组输入数据的引用,导致垃圾收集器无法工作。
故事
尝试通过递归实现复杂生成器而不跟踪深度,在处理真正的大数据时导致栈限制超出,而不是预期的“惰性”遍历。