加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

考虑到Perl中的包名,如何从包中调用子例程?

发布时间:2020-12-15 21:48:19 所属栏目:大数据 来源:网络整理
导读:给定一个包含表示包名称的字符串的变量,如何调用包的特定子例程? 这是我发现的最接近的事情: package MyPackage;sub echo { print shift;}my $package_name = 'MyPackage';$package_name-echo('Hello World');1; 这段代码的问题是子程序被称为类方法;包名
给定一个包含表示包名称的字符串的变量,如何调用包的特定子例程?

这是我发现的最接近的事情:

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”的符号引用.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读