在Perl中使用自调用匿名函数是一个好习惯吗?

时间:2013-11-29 16:02:19

标签: perl

在JavaScript中使用自调用匿名函数来扩展变量等是一种常见做法:

;(function() {
  ...
})();

在Perl中使用这些函数是一个好习惯吗?

(sub {
  ...
})->();

或者出于某种原因使用main子程序更好吗?

sub main {
  ...
}

main();

4 个答案:

答案 0 :(得分:6)

Perl有JS缺乏的词汇范围机制。你最好简单地将你想要的代码封装在一个块中,例如:

{
    my $localvar;
    . . .
}

在这种情况下,$localvar在这些大括号之外将完全不可见;这也是可以用来本地化内置变量的机制,例如$/

{
    local $/ = undef;
    #reading from a file handle now consumes the entire file
}
#But not out here

(旁注:永远不要全局设置$/。如果你在完成后忘记将其设置回来,或者在恢复之前调用其他代码,它会以微妙和可怕的方式破坏事物。)< / p>

在perl中,最好的做法是在有意义的时候将东西放入潜艇;当它没有意义或不必要地使代码复杂化时,词汇块确保范围;如果你确实需要匿名子程序(通常用于回调或类似),那么你可以做my $subref = sub { . . . };甚至只是将子声明直接粘贴到函数参数中:do_something(callback => sub { . . . });

注意:另请参阅ysth's answer,了解自行调用匿名潜艇的资源相关优势。

答案 1 :(得分:4)

由于perl提供了词法范围的变量(并且,从5.18开始,词汇命名为subs),因此没有确定范围的原因。

我能想到的唯一理由就是内存管理;如果有问题的子句是一个闭包(引用至少一个外部词法变量),那么sub使用的任何内存都将被完全释放而不是保留以便在下次调用时重用:

$ perl -MDevel::Peek -wle'sub { my $x; Dump $x; $x = 42 }->() for 1..2'
SV = NULL(0x0) at 0x944a88
  REFCNT = 1
  FLAGS = (PADMY)
SV = IV(0x944a78) at 0x944a88
  REFCNT = 1
  FLAGS = (PADMY)
  IV = 42
$ perl -MDevel::Peek -wle'my $y; sub { $y if 0; my $x; Dump $x; $x = 42 }->() for 1..2'
SV = NULL(0x0) at 0x259d238
  REFCNT = 1
  FLAGS = (PADMY)
SV = NULL(0x0) at 0x259d220
  REFCNT = 1
  FLAGS = (PADMY)

虽然如果你不关心记忆,这将是一个缺点。

答案 2 :(得分:3)

这不是闻所未闻,但也不常见。要临时限制变量范围,使用带有my变量声明的块更为常见:

...
{
    my $local_variable;
    ...
}

答案 3 :(得分:2)

在Javascript中,自调用函数有两个用途:

  1. 变量范围。 var声明被提升到第一个封闭函数的范围或全局范围。因此,

    function () {
      if (true) {
        var foo = 42
      }
    }
    

    相同
    function () {
      var foo
      if (true) {
        foo = 42
      }
    }
    

    - 通常是不受欢迎的影响。

  2. 表达水平的陈述。有时你需要多个语句来计算某些东西,但是想在表达式中这样做。

    largeObject = {
      ...,
      // sum from 1 to 42
      sum: (function(n){
        var sum = 0;
        for(var i = 1; i <= n; i++)
          sum += i;
        return sum;
      })(42),
      ...,
    };
    
  3. Perl不需要将自调用函数作为作用域机制,因为任何大括号都会引入新的作用域。在语句级别始终允许裸块:​​

    ...
    my $foo = 10;
    {
      my $foo = 42;
    }
    $foo == 10 or die; # lives
    

    Perl减少了对自调用函数的需求,因为do BLOCK内置函数将语句引入表达式:

    %large_hash = (
      ...,
      sum => do {
        my $sum = 0;
        $sum += $_ for 1 .. 42;
        $sum;
      },
      ...,
    );
    

    但是,你有时会想要在这样的一个块中进行短路。当return退出周围的子程序(不是块)时,它在这里非常有用。例如,在memoized函数中:

    # moronic cached division by two
    my %cache;
    sub lookup {
      my $key = shift;
      return $cache{$key} //= sub {
        for (1 .. 100) {
          return $_ if $_ * 2 == $key
        }
        return;
      }->();
    }