类中的Perl原型子例程

类中的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

我试图在不实例化对象的情况下从类调用原型函数。my class
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;