Perl原型子程序在课堂上

use*_*275 2 perl class subroutine subroutine-prototypes

我试图从类中调用原型函数而不实例化对象.我班的一个例子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;
Run Code Online (Sandbox Code Playgroud)

我想从脚本中调用原型main.pl:

use strict;
use warnings;

use MyClass;

myprot {
        print "myprot\n";
};
Run Code Online (Sandbox Code Playgroud)

我收到错误:

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.
Run Code Online (Sandbox Code Playgroud)

我真的不明白未定义的子程序错误:使用use,import调用它来定义原型main.pl.我也真的不明白未初始化的值错误.我很乐意得到一些解释.

ike*_*ami 8

你正在寻找出口商.

package MyClass;
use strict;
use warnings;

use Exporter qw( import );

our @EXPORT = qw( myprot );

sub myprot(&) {
    my ($f) = @_;
    $f->();
}

1;
Run Code Online (Sandbox Code Playgroud)

我通常使用@EXPORT_OK(需要使用use MyClass qw( myprot );)而不是默认导出.


Sch*_*ern 5

那段代码中有一堆粗略的东西.

未经检查的使用eval意味着如果失败,你永远不会知道.eval应该用作eval "code" or die $@.你会发现它引发了一个错误,因为当你弄乱符号表时,严格不喜欢它(*name = \&code正是这样做).

使用eval导出子程序是过度的.eval STRING是一个潜在的安全漏洞,应该作为最后的手段使用(eval BLOCK很好).您可以在没有eval的情况下操作符号表,但严格不会喜欢使用符号引用.

my $caller = "foo";
*{"${caller}::myprot"} = \&MyClass::myprot;
# Can't use string ("foo::myprot") as a symbol ref while "strict refs" in use...
Run Code Online (Sandbox Code Playgroud)

你必须首先关闭严格.这通常称为"混叠".

no strict 'refs';
*{$caller.'::myprot'} = \&myprot;
Run Code Online (Sandbox Code Playgroud)

预先设置原型是不必要的,别名将为您处理.

事实证明这一切都是不必要的,有很多模块可以帮到你.最常见的是Exporter和Perl.这使您的自定义import不必要.

use Exporter 'import';
our @EXPORT = qw(myprot);
Run Code Online (Sandbox Code Playgroud)

其他一般提示......

应该避免硬编码类中的类的名称(即\&MyClass::myprot应该只是\&myprot).这使得更改类或移动代码变得更加困难.

不鼓励使用类和导出功能的混合模块.它们更难以使用,测试和记录并产生奇怪的副作用.你应该把myprot它放进自己的模块中.

  • @ user1981275我不能建议您一般避免使用eval并避免重新发明Exporter.以微妙的方式出错是非常非常非常容易的,也可能是维修坑.编写自己的导入是有正当理由的,但这不是其中之一. (3认同)
  • 导出器不需要继承,所以不要使用它:`使用导出器'导入';`,而不是'使用父'导出器';` (2认同)
  • 不,导入被调用,你的重新发明轮子而不是使用导出器失败了 (2认同)