给定一个包含表示包名称的字符串的变量,如何调用包的特定子例程?
这是我发现的最接近的事情:
package MyPackage; sub echo { print shift; } my $package_name = 'MyPackage'; $package_name->echo('Hello World'); 1;
这段代码的问题是子程序被称为类方法;包名称作为第一个参数传入.我想从包名称调用子例程,而不会隐式传入特殊的第一个参数.
解决方法
Perl方法调用只是常规子例程,它将invocant作为第一个值.
use strict; use warnings; use 5.10.1; { package MyPackage; sub new{ bless {},shift } # overly simplistic constructor (DO NOT REUSE) sub echo{ say @_ } } my $package_name = 'MyPackage'; $package_name->echo; my $object = $package_name->new(); $object->echo; # effectively the same as MyPackage::echo($object)
MyPackage MyPackage=HASH(0x1e2a070)
如果要在没有调用者的情况下调用子例程,则需要以不同方式调用它.
{ no strict 'refs'; ${$package_name.'::'}{echo}->('Hello World'); &{$package_name.'::echo'}('Hello World'); } # only works for packages without :: in the name $::{$package_name.'::'}{echo}->('Hello World'); $package_name->can('echo')->('Hello World');
> can
方法返回对子例程的引用,如果已在调用者上调用该子例程,则该子例程将被调用.然后可以单独使用coderef.
my $code_ref = $package_name->can('echo'); $code_ref->('Hello World');
使用can
有一些注意事项:
>可以被包或它继承的任何类重写.
>定义方法的包可能与调用者不同.
这实际上可能是您正在寻找的行为.
>另一种方法是使用称为symbolic reference的东西.
{ no strict 'refs'; &{ $package_name.'::echo' }('Hello World'); }
通常不建议使用符号引用.部分问题在于,如果您不打算使用符号引用,则可能会意外地使用符号引用.这就是为什么你不能使用严格的“参考”;有效.
这可能是做你想做的最简单的方法.
>如果您不想使用符号引用,则可以使用Stash.
$MyPackage::{echo}->('Hello World'); $::{'MyPackage::'}{echo}->('Hello World'); $main::{'MyPackage::'}{echo}->('Hello World'); $main::{'main::'}{'MyPackage::'}{echo}->('Hello World'); $main::{'main::'}{'main::'}{'main::'}{'MyPackage::'}{echo}->('Hello World');
唯一的问题是你必须拆分$package_name ::
*Some::Long::Package::Name::echo = \&MyPackage::echo; $::{'Some::'}{'Long::'}{'Package::'}{'Name::'}{echo}('Hello World'); sub get_package_stash{ my $package = shift.'::'; my @package = split /(?<=::)/,$package; my $stash = \%:: ; $stash = $stash->{$_} for @package; return $stash; } get_package_stash('Some::Long::Package::Name')->{echo}('Hello World');
这不是一个大问题.快速查看CPAN后,您会找到Package::Stash.
use Package::Stash; my $stash = Package::Stash->new($package_name); my $coderef = $stash->get_symbol('&echo'); $coderef->('Hello World');
(Pure Perl版Package::Stash使用符号引用,而不是Stash)
甚至可以创建子例程/方法的别名,就好像是从使用Exporter的模块导入的:
*echo = \&{$package_name.'::echo'}; echo('Hello World');
我建议限制别名的范围:
{ local *echo = \&{$package_name.'::echo'}; echo('Hello World'); }
这是一个例外,您可以使用带有严格“refs”的符号引用.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。