为什么我对包子的本地化重新定义没有生效?

Dyl*_*ali 7 perl

鉴于以下Perl计划:

package Foo;
use strict;
use warnings;

sub new {
    my ($class) = @_;
    return bless {}, $class;
}

sub c {
    print "IN ORIG C\n";
}

sub DESTROY {
    print "IN DESTROY\n";
    c();
}

1;

package main;
use strict;
use warnings;
no warnings qw/redefine once/;

local *Foo::c = sub { print "IN MY C\n" };
my $f = Foo->new();
undef $f;
Run Code Online (Sandbox Code Playgroud)

我期望输出为:

IN DESTROY
IN MY C
Run Code Online (Sandbox Code Playgroud)

但我实际得到的输出为:

IN DESTROY
IN ORIG C
Run Code Online (Sandbox Code Playgroud)

问:为什么我的本地化重新定义Foo::c没有生效?

yst*_*sth 6

编译perl代码时,会查找包变量/符号的globs(并根据需要创建),并直接从编译的代码中引用.

因此,当您(暂时)*Foo::c在运行时替换符号表条目时,所使用的所有已编译代码*Foo::c仍然使用原始glob.但是do/require'd代码或eval STRING或符号引用不会.

(与Perl中的符号表中删除名称后的Access包变量非常相似,请参见示例.)


Mat*_*all 2

这是 perl 中的一个错误,将在 5.22 中修复(请参阅下面 Leon 的评论)。

发生这种情况是因为undef $f;实际上并没有释放和销毁$f,它只是将其标记为准备好被nextstate操作释放。

nextstate操作大致存在于每个语句之间,它们的作用是清理堆栈等。

在您的示例中,由于undef $f是文件中的最后一件事,因此在它之后没有 nextstate,因此您的本地析构函数在调用 的析构函数之前超出了范围$f(或者,发生的全局销毁只是不知道您的本地析构函数改变。)

当您在之后添加打印语句时undef $fnextstate打印之前的操作将调用本地析构函数。

您可以在https://gist.github.com/calid/aeb939147fdd171cffe3#file-04-diff-concise-outnextstate的示例中 查看附加内容。

您还可以通过检查caller()您的DESTROY方法来查看此行为:

sub DESTROY {
  my ($pkg, $file, $line) = caller;
  print "Destroyed at $pkg, $file, $line\n";
  c();
}

mhorsfall@tworivers:~$ perl foo.pl
Destroyed at main, foo.pl, 0
IN DESTROY
IN ORIG C

mhorsfall@tworivers:~$ echo 'print "hi\n"' >> foo.pl
mhorsfall@tworivers:~$ perl foo.pl
Destroyed at main, foo.pl, 30
IN DESTROY
IN MY C
hi
Run Code Online (Sandbox Code Playgroud)

(第 30 行是print "hi\n"

希望这能让大家对此有所了解。

干杯。