在_fact前面*的确切功能/目的是什么以及它如何被等效地写出来?
sub fact { my ($n) = @_; local *_fact = sub { my ($n,$prod) = @_; return $prod if $n == 0; return _fact($n-1,$n*$prod); }; return _fact($n,1); } fact($n);
解决方法
理想情况下,函数的作者会喜欢使用
sub fact { my ($n) = @_; my $_fact; $_fact = sub { my ($n,$prod) = @_; return $prod if $n == 0; return $_fact->($n-1,$n*$prod); }; return $_fact->($n,1); }
不幸的是,这有内存泄漏. anon sub引用了$_fact,它保存了对匿名子的引用.需要清除$_fact以在退出时中断引用.
sub fact { my ($n) = @_; my $_fact; $_fact = sub { my ($n,$n*$prod); }; my $rv; my $e = eval { $rv = $_fact->($n,1); 1 } ? undef : ($@ || 'Unknown'); $_fact = undef; die $e if $e return $rv; }
但那是个丑陋的!避免此问题的一种方法是使用Y combinator.避免问题的一种更简单的方法是将代码引用存储在包变量而不是词法变量中(因为只有子句捕获词法变量).这就是您发布的代码所做的事情.请记住
*_fact = sub { ... };
基本上是一个运行时版本
sub _fact { ... }
两者都将子分配给符号_fact的CODE槽.
也就是说,5.16引入了更好的解决方案:
use feature qw( current_sub ); sub fact { my ($n) = @_; my $_fact = sub { my ($n,$prod) = @_; return $prod if $n == 0; return __SUB__->($n-1,1); }