Perl 的“Package::->method()”(冒号-冒号-箭头)表示法

amp*_*ine 7 perl perlop

我正在阅读attributes模块的文档,并遇到了一个我从未见过的方法调用符号:

use attributes ();
attributes::->import(__PACKAGE__, \$x, 'Bent');
Run Code Online (Sandbox Code Playgroud)

该文档没有提供此语法的解释。

经调查,它似乎Package::->method()相当于Package->method()'Package'->method()

它似乎也相当于Package::method('Package'),前提是该方法不是继承的。

问题 0:使用Package::->method()符号有什么实际原因吗?


编辑:我发现如果您有一个与包同名的常量,Package::->method()则调用包方法,而Package->method()调用常量上的方法。

use constant Foo => bless {}, 'Bar'; # or just => 'Bar'

print Foo::->method(); # prints 'Foo method'
print 'Foo'->method(); # prints 'Foo method'
print Foo->method();   # prints 'Bar method'

package Foo;
sub method { 'Foo method' }
package Bar;
sub method { 'Bar method' }
Run Code Online (Sandbox Code Playgroud)

奇怪的是use warnings,这个脚本会给出“Bareword 'Foo::'引用不存在的包”警告,但无论如何都会执行它,这让我更加困惑。

更奇怪的是,Foo::method();在该Foo::->method()行之前添加该行可以消除“Bareword”警告

问题1:有人可以解释一下这是怎么回事吗?

对于后代来说,这是 Perl v5.38.0。

ike*_*ami 9

Package::->method是一种(稍微)更安全的书写方式Package->method


文档对此做出了回答。Perl 如何解析未加引号的裸词?也相关。

Foo::相当于"Foo",但它还检查名称空间是否Foo存在。

Foo也意味着"Foo",但前提是它没有任何其他含义。before 时它不受限制->,但这里没有什么特别的Foo。因此,如果您有一个名为 的子程序Foo,它将调用该子程序。如果您有一个名为 的常量Foo,则会使用它。

总之,

  • Foo::->method总是意味着"Foo"->method
  • Foo->method通常意味着"Foo"->method.
  • Foo->method也可能意味着Foo()->method

由此,我们得出使用 的以下原因Foo::

  • 通过使用Foo::,您可以避免意外调用子程序。(这包括常量。)

    在实践中发生这种情况的可能性非常小。人们希望,这可以在测试中找到。但考虑到这种情况的罕见性,一旦发生可能会令人困惑。

  • 通过使用Foo::,您可以表明这不是子调用。

    但当你看到某种形式的东西时,这已经是假设了Foo->method当它是子调用时发出信号更为重要(例如,通过使用Foo()->method)。

  • 通过使用Foo::,如果您忘记加载模块,您可以获得更好的诊断。

    你得到

    Bareword "Foo::" refers to nonexistent package at ...
    Can't locate object method "method" via package "Foo" (perhaps you forgot to load "Foo"?)` at ...
    
    Run Code Online (Sandbox Code Playgroud)

    代替

    Can't locate object method "method" via package "Foo" (perhaps you forgot to load "Foo"?)` at ...
    
    Run Code Online (Sandbox Code Playgroud)

    我说得更好吗?这对我来说更吵。