神秘的*在嵌套子的前面

use*_*716 5 perl typeglob

在_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);
Run Code Online (Sandbox Code Playgroud)

ike*_*ami 11

理想情况下,函数的作者会喜欢使用

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);
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这有内存泄漏.anon sub有一个引用$_fact,它包含对匿名sub的引用.$_fact需要清除以在退出时打破引用.

sub fact {
   my ($n) = @_;

   my $_fact;
   $_fact = sub {
       my ($n, $prod) = @_;
       return $prod if $n == 0;
       return $_fact->($n-1, $n*$prod);
   };

   my $rv;
   my $e = eval { $rv = $_fact->($n, 1); 1 } ? undef : ($@ || 'Unknown');
   $_fact = undef;
   die $e if $e
   return $rv;       
}
Run Code Online (Sandbox Code Playgroud)

但那是个丑陋的!避免该问题的一种方法是使用Y组合器.避免该问题的一种更简单的方法是将代码引用存储在包变量而不是词法变量中(因为只有子句捕获词法变量).这就是您发布的代码所做的事情.请记住

*_fact = sub { ...  };
Run Code Online (Sandbox Code Playgroud)

基本上是一个运行时版本

sub _fact { ... }
Run Code Online (Sandbox Code Playgroud)

两者都将子分配给符号的CODE槽_fact.

也就是说,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, $n*$prod);
   };

   return $_fact->($n, 1);
}
Run Code Online (Sandbox Code Playgroud)


Сух*_*й27 2

检查typeglob 别名

上面的示例应该使用匿名子例程/闭包编写:

sub fact {
   my ($n) = @_;

   my $_fact;
   $_fact = sub {
       my ($n, $prod) = @_;
       return $prod if $n == 0;
       return __SUB__->($n-1, $n*$prod);
   };

   return $_fact->($n, 1);
}
Run Code Online (Sandbox Code Playgroud)