Perl的__PACKAGE__特殊字,不能用作命名空间?

时间:2013-04-23 06:23:18

标签: perl

我看到__PACKAGE__将被编译为包名。

为什么代码:

Foo::bar() 

可以工作。但代码:

__PACKAGE__::bar() 

会产生错误:

Undefined subroutine &__PACAKGE__::bar called

调用者在Foo包中,所以__PACKAGE__将是Foo;

希望你能解释一下:)

让我添加一个例子来解释这个场景:

$ perl -e 'package Foo ; sub bar { print "hello\n" } ; __PACKAGE__::bar()'  
Undefined subroutine &__PACKAGE__::bar called at -e line 1.

$ perl -e 'package Foo ; sub bar { print "hello\n" } ; Foo::bar()'
hello

3 个答案:

答案 0 :(得分:4)

你似乎错了。 Foo::bar()__PACKAGE__::bar()的工作方式完全相同。

$ perl -e'sub Foo { "main" }  Foo::bar()'
Undefined subroutine &Foo::bar called at -e line 1.

$ perl -e'__PACKAGE__::bar()'
Undefined subroutine &__PACKAGE__::bar called at -e line 1.

$ perl -E'package Foo; sub bar { say "hello" } Foo::bar()'
hello

$ perl -E'package __PACKAGE__; sub bar { say "hello" } __PACKAGE__::bar()'
hello

他们都在指定的包(barFoo)中调用__PACKAGE__Foo__PACKAGE__都不被视为函数调用。

这是因为Foo__PACKAGE__都不是代码中的单词。如果您想从bar返回的包中调用__PACKAGE__,可以使用

bar()

如果你有一个包含任意包的var(可能从__PACKAGE__获得),你可以使用

(\&{ $pkg . '::bar' })->();

答案 1 :(得分:3)

您似乎误解了__PACKAGE__被视为special literal的时间。

special literals只有"separate token"才具有特殊含义。

use 5.10.0;
use strict;
use warnings;

say 'in package: ', __PACKAGE__;

sub bar{ say 'this is the one you might be expecting' }

__PACKAGE__::bar(); # not a separate token

{
  package __PACKAGE__;
  sub bar{ say 'this is the one you actually get' }
}
in package: main
this is the one you actually get

有几种方法可以解决这个问题:

bar(); # recommended

{
  no strict 'refs';
  *{__PACKAGE__.'::bar'}->(); # symbol ref

  ${__PACKAGE__.'::'}{bar}->(); # magical %package:: variable
}

__PACKAGE__->can('bar')->(); # may get 'bar' from a parent package

__PACKAGE__->bar(); # same as __PACKAGE__->can('bar')->(__PACKAGE__)


our $symbol_table = do{ no strict 'refs'; \%{__PACKAGE__.'::'} };

$symbol_table->{bar}->();

真的很少有理由使用__PACKAGE__

答案 2 :(得分:0)

在包(包括__PACKAGE__)中搜索函数(可能是方法)的规范方法是使用can方法。在类名或实例上调用时,它返回对函数/方法的引用;然后你可以取消引用它来调用实际的函数。在你的情况下,这可以是

perl -E 'sub bar { say "hello" } __PACKAGE__->can("bar")->()'

这与Michael Prz在评论中建议的区别在于第一个论点的处理。例如,当您尝试

perl -E 'sub bar { say "hello " . shift } __PACKAGE__->bar("name")'

你得到了

hello main

因为main是调用参数。然而

perl -E 'sub bar { say "hello " . shift } __PACKAGE__->can("bar")->("name")'

做你期望的事。