在Perl中立即调用函数表达式(IIFE)的最佳方法?

时间:2019-06-10 20:51:07

标签: perl anonymous-function

借用Java术语,在perl中实现IIFE的“最佳实践”是什么?

下面的测试代码是一个简单的循环,它调用匿名子程序并立即执行以构建子程序数组(该子程序仅返回循环索引)。这主要是我想要的,但是我需要使用一个中间变量(而不是使用@_,它会在内部函数上更改)。

use warnings;
use strict;
my @funcs;
for(my $i=0;$i<3;$i++) {
    sub  {
        my $index=shift;
        $funcs[$index]=sub {$index};
    }
    -> ($i);
}

for (@funcs) {
    print &$_()."\n";
}
#Output
0
1
2

我知道我可以使用map来解决此问题。但是抛开这些,还有更好的方法吗?

更新

感谢@ikegami强调了一些要点。

仅出于以后对该问题的看法,我对此的看法:

“迭代器” for循环的作用域(是否是地图?)与“ c样式” for循环的作用域不同。这样就完全不需要IIFE即可清理代码。亲爱的。

更新2

以下代码显示了我所看到的差异。我并不是说一个比另一个更好,但是很高兴知道。我的输出是0 1 2,但第一个仅重复$ i的最后一个值(++运算符后为3)。

use warnings;
use strict;
my @funcs;
print "C loop direct assignment of sub\n";
for(my $i=0;$i<3;$i++) {
    $funcs[$i]= sub {$i};
}
print &$_()."\n" for @funcs;

print "C loop direct assignment of sub with variable\n";
for(my $i=0;$i<3;$i++) {
    my $index=$i; #assignment/copy
    $funcs[$index]= sub {$index};
}
print &$_()."\n" for @funcs;

print "For loop interator\n";
@funcs=[];
for my $i (0..2) {
    $funcs[$i]=sub {$i};
}
print &$_()."\n" for @funcs;

print "C loop with IIFE assignment\n";
@funcs=[];
for (my $i=0;$i<3;$i++) {
    sub  {
    my $index=shift;
        $funcs[$index]=sub {$index};
    }
    -> ($i);
}
print &$_()."\n" for @funcs;

出局是

C loop direct assignment of sub                                                                                                                                          
3                                                                                                                                                                        
3                                                                                                                                                                        
3         
C loop direct assignment of sub with variable                                                                                                                            
0                                                                                                                                                                        
1                                                                                                                                                                        
2                                                                                                                                                                            
For loop interator                                                                                                                                                       
0                                                                                                                                                                        
1                                                                                                                                                                        
2                                                                                                                                                                        
C loop with IIFE assignment                                                                                                                                                           
0                                                                                                                                                                        
1                                                                                                                                                                        
2        

1 个答案:

答案 0 :(得分:7)

相当于Perl的

(function () {
   var x = ...;
   ...
})();

sub {
   my $x = ...;
   ...
}->();

也就是说,IIFE只是Perl根本不需要的解决方法。

(function () {
   var x = ...;
   ...
})();

是一种解决方法

{
   my $x = ...;
   ...
}

var result = (function () {
   return ...;
})();

是一种解决方法

my $result = do {
   ...
};

您似乎正在尝试翻译类似以下内容的内容:

let funcs = [];
for (let i=0; i<3; ++i) {
   (function() {
      var index = i;
      funcs.push( function() { return index; } );
   })();
}

for (let func of funcs)
   console.log(func());

以下是直接翻译:

my @funcs;
for (my $i=0; $i<3; ++$i) {
   sub {
      my $index = $i;
      push @funcs, sub { $index };
   }->();
}

say $_->() for @funcs;

但是使用IIFE根本没有意义。只需使用以下内容即可:

my @funcs;
for (my $i=0; $i<3; ++$i) {
   my $index = $i;
   push @funcs, sub { $index };
}

say $_->() for @funcs;

现在,人们倾向于在Perl中避免使用C风格的for循环,因为使用foreach循环更具可读性(并且效率更高!)。它还使解决方案更加简单,因为foreach循环的循环变量的作用域是循环体,而不是循环语句。

my @funcs;
for my $i (0..2) {
   push @funcs, sub { $i };
}

say $_->() for @funcs;