递归子程序参考

时间:2014-09-10 05:40:46

标签: perl recursion

我用perl 5.8(codepad)和perl 5.16测试了以下代码。可能有一些更深层次的原则我不知道,我很好奇这种行为背后的逻辑是什么。感谢。

以下简单的递归子例程引用

use strict;
use warnings;

my $fact = sub {
    my $n = shift;
    if ($n == 0) {
         return 1;
    }
    return $n * $fact->($n-1);
};

print $fact->(100);

导致错误

Global symbol "$fact" requires explicit package name at line 9.
Execution aborted due to compilation errors.

在定义变量之前声明变量不会产生此错误。

use strict;
use warnings;

my $fact;
$fact = sub {
    my $n = shift;
    if ($n == 0) {
        return 1;
    }
    return $n * $fact->($n-1);
};

print $fact->(100);

1 个答案:

答案 0 :(得分:5)

my 返回新的词法,因此它可以用于在声明它的同一语句中将分配给。但是,对 name 的任何进一步引用仅从下一个语句开始解析为该词汇。

将声明分开:

my $fact;
$fact = sub { ... $fact ... }

这条规则实际上有时是有用的;你可以有一个外部词汇和一个内部词汇,并在两者之间分配:

my $foo = 42;
{
    my $foo = $foo;
    $foo += 42;
    print "foo is $foo\n";
}
print "foo is $foo\n";

如果您有最新版本的Perl,则实际上不需要在子例程中访问$fact,因为__SUB__伪常量提供对当前子例程的引用。

use 5.016;
my $fact = sub {
    my $n = shift;
    if ($n == 0) {
        return 1;
    }
    return $n * __SUB__->($n-1);
};

请注意,在第一个示例中(在sub中使用$fact变量),会创建一个引用周期,这可能会导致Perl随着时间的推移泄漏内存。 __SUB__是一种解决该问题的相当简洁的方法。 (该问题的其他解决方案包括the Y-combinatorreference weakening。)