类中的Perl原型子例程
我试图在不实例化对象的情况下从类调用原型函数。my class类中的Perl原型子例程,perl,class,subroutine,subroutine-prototypes,Perl,Class,Subroutine,Subroutine Prototypes,我试图在不实例化对象的情况下从类调用原型函数。my classMyClass的一个示例: package MyClass; use strict; use warnings; sub import{ my $class = shift; my ($caller) = caller(); eval "sub ${caller}::myprot(\&);"; eval "*${caller}::myprot = \&M
MyClass
的一个示例:
package MyClass;
use strict;
use warnings;
sub import{
my $class = shift;
my ($caller) = caller();
eval "sub ${caller}::myprot(\&);";
eval "*${caller}::myprot = \&MyClass::myprot;";
}
sub myprot (&) {
my ($f) = @_;
$f->();
}
1;
我想从脚本main.pl
调用原型:
use strict;
use warnings;
use MyClass;
myprot {
print "myprot\n";
};
我得到了错误:
Use of uninitialized value in subroutine entry at MyClass.pm line 14.
Use of uninitialized value in subroutine entry at MyClass.pm line 14.
Undefined subroutine &main::myprot called at main.pm line 8.
我不太理解未定义的子例程错误:对于use
,调用了import
,它定义了main.pl
的原型。我也真的不理解未初始化的值错误。
我很乐意作一些解释。你确定你真的想这样做吗 问题是,双引号将占用全局赋值中的反斜杠
eval "*${caller}::myprot = \&MyClass::myprot;"
应该是
eval "*${caller}::myprot = \\&MyClass::myprot;"
但是请不要让我调试你的代码 那段代码中有很多粗略的东西 不加检查地使用eval意味着如果失败,你永远不会知道。eval应用作
eval“code”或die$@
。您会发现它抛出了一个错误,因为strict不喜欢您弄乱符号表(这就是*name=\&code
所做的)
使用eval导出子例程是过分的。eval STRING是一个潜在的安全漏洞,应作为最后手段使用(eval BLOCK可以)。您可以在不使用eval的情况下操作符号表,但strict不喜欢使用符号引用
my $caller = "foo";
*{"${caller}::myprot"} = \&MyClass::myprot;
# Can't use string ("foo::myprot") as a symbol ref while "strict refs" in use...
你必须先关掉“严格”。这通常被称为“别名”
事先设置原型是不必要的,alias将为您处理它
事实证明这是完全不必要的,有很多模块可以为您实现这一点。最常见的是Perl,它随Perl一起提供。这使得您的自定义导入不必要
use Exporter 'import';
our @EXPORT = qw(myprot);
其他一般提示
应避免硬编码类中类的名称(即,\&MyClass::myprot
应为\&myprot
)。这使得更改类或移动代码变得更加困难
不鼓励同时具有类和导出功能的混合模块。它们更难使用、测试和记录,并产生奇怪的副作用。您应该将myprot放入自己的模块中。您正在寻找出口商
package MyClass;
use strict;
use warnings;
use Exporter qw( import );
our @EXPORT = qw( myprot );
sub myprot(&) {
my ($f) = @_;
$f->();
}
1;
我通常使用@EXPORT\u OK
(需要使用使用MyClass qw(myprot);
)而不是默认导出。我认为您需要myprot(sub{print“myprot\n”})代码>并且您还需要从MyClass包中导出myprot,这样做@KeepCalmAndCarryOn:这不是有效的Perl-可能您打算使用大括号{..}
而不是圆括号(..)
。不-他想要MyClass
声明一个函数myprot
,该函数将一个代码块作为其唯一参数。但是我同意他不应该让它看起来像一个没有sub
的子例程定义。我相信你不会期望在实时代码中实际使用它吧?我的回答解释了为什么它对你不起作用,但是你真的不能在实验之外做这样的事情;只有在自动加载或稍后将定义子例程时才需要转发声明,但在这里您将立即导出它。但是,只需使用Exporter而不是您的错误消息来自这样一个事实,即您的求值是在调用方填充子例程表之前发生的。仔细研究并记住,use
被认为大致等于BEGIN{require module;module::import(args)}
。另外,你的eval
s漏掉了一些反斜杠。这是一个整洁的总结。但我怀疑(希望)OP是在玩弄Perl的神秘角落,并没有期望在实时代码中使用它。@Borodin我对相反的情况很有信心。幸运的是,他们现在都有了答案导出器不需要继承,所以不要使用它:use Exporter'import'代码>,而不是使用父级“导出器”代码>否,调用了导入,您重新发明了轮子,而不是仅使用Exporterfailed@user1981275我无法推荐足够多的方法来避免一般的eval和重新投资出口商。它非常、非常、非常容易以微妙的方式出错,可能是一个维修坑。有充分的理由编写您自己的导入,但这不是其中之一。这很有效,谢谢!但我仍然不知道导出器的确切功能。例如,如果我不使用使用,但是需要MyClass代码>和MyClass->import()
,然后执行import
,但我无法调用myprot
您试图在声明myprot
(及其原型)之前编译对myprot
的调用<代码>使用MyClass
基本上是BEGIN{require MyClass;MyClass->import();}
,因此您将导入移到了运行时。@user1981275长话短说,Exporter为您的模块提供了一个导入例程,它可以完成您所需的大部分工作。如果您不了解如何使用
和导入
交互,请不要编写自己的导入例程。这些文档可能有助于理解。也是一个警告的陷阱,如果没有坚实的理解,就不应该使用。@ikegami ok,现在对我来说有意义了。
package MyClass;
use strict;
use warnings;
use Exporter qw( import );
our @EXPORT = qw( myprot );
sub myprot(&) {
my ($f) = @_;
$f->();
}
1;