我正在尝试使用接收子例程的方法创建一个模块并重新定义它.我在主脚本中重新定义子例程没有问题,但是相同的语法似乎在方法内部不起作用:
use strict;
use warnings;
use ReDef;
sub orig{
print "Original!\n";
}
orig;
*orig=sub{print "not Original!\n";};
orig;
ReDef::redef(\&orig);
orig;
Run Code Online (Sandbox Code Playgroud)
package ReDef;
use strict;
use warnings;
sub redef {
my $ref=shift;
*ref = sub {print "Redefined!";}
}
1;
Run Code Online (Sandbox Code Playgroud)
perl main.pl
Original!
Subroutine main::orig redefined at main.pl line 9.
not Original!
not Original!
Run Code Online (Sandbox Code Playgroud)
ReDef :: redef()不会重新定义.我看到它的方式,*ref是一个coderef并指定给它另一个子程序应该改变main :: orig();
什么是正确的语法?
你的redef功能应该是这样的:
package ReDef;
use strict;
use warnings;
sub redef {
my $ref = shift;
no warnings qw(redefine);
*$ref = sub { print "Redefined!" };
}
Run Code Online (Sandbox Code Playgroud)
你应该不要这样称呼它:
ReDef::redef(\&orig);
Run Code Online (Sandbox Code Playgroud)
相反,你必须这样调用它:
ReDef::redef(\*orig);
Run Code Online (Sandbox Code Playgroud)
为什么?当你打电话时orig,你正在通过符号表查找名称"orig",因此该redef函数需要改变符号表,以便它可以将该名称指向不同的代码位.Globrefs基本上是指向一小部分符号表的指针,所以这就是你需要传递给它的东西ReDef::redef.
作为一个类比,想象一下,当你想知道刘易斯战役的日期时,你的程序是去图书馆,在目录中查看一本关于13世纪英国战争的书籍的书架地址,去那个架子,并查看约会...瞧1264年5月14日!现在,想象一下,我想给你提供更改的信息.简单地定义一个新的coderef就像在书架上放一本新书:它不会欺骗你,因为目录仍然指向你的旧书.我们也需要改变目录.
UPDATE
你可以使用原型让它变得更漂亮.通常不建议使用原型,但这似乎对他们来说是非邪恶的......
use strict;
use warnings;
sub ReDef::redef (*) {
my $ref = shift;
no warnings qw(redefine);
*$ref = sub { print "Redefined!\n" };
}
sub orig { print "Original!\n" }
orig;
ReDef::redef *orig; # don't need the backslash any more
orig;
Run Code Online (Sandbox Code Playgroud)
这对我有用:
\n\nuse v5.16;\nuse strict;\nuse warnings;\n\npackage Redef;\n\nsub redef {\n my $ref = shift;\n ${$ref} = sub { say "Redefined!"; }\n}\n\npackage main;\n\nmy $orig = sub { say "Original!"; };\nRedef::redef(\\$orig);\n$orig->(); # Redefined!\nRun Code Online (Sandbox Code Playgroud)\n\n虽然它\xe2\x80\x99s只是反复试验的结果,但我\xe2\x80\x99d很高兴看到更好的答案。
\n\n也许让您感到困惑的是 typeglob 运算符*. 在 Perl 中,您使用印记 ( ${$scalar_ref}, @{$array_ref}) 取消引用,并且该*运算符用于符号表技巧 \xe2\x80\x93 ,它也可以在您的情况下使用,请参阅 @tobyink 的答案。