Perl的“Package::->method()”(colon-colon-arrow)表示法

nlejzf6q  于 2023-10-24  发布在  Perl
关注(0)|答案(1)|浏览(122)

我在阅读documentation for the attributes module时,偶然发现了一个我从未见过的方法调用符号:

use attributes ();
attributes::->import(__PACKAGE__, \$x, 'Bent');

文档未提供此语法的解释。
在研究中,似乎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' }

奇怪的是,在use warnings中,这个脚本会给予一个“Bareword 'Foo::' referes to nonexistent package”警告,但 * 无论如何都会执行它 *,这让我更加困惑。
更奇怪的是,在Foo::->method()行 * 之前添加Foo::method();行 * 可以消除“Bareword”警告 *。

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

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

8wtpewkr

8wtpewkr1#

Package::->method是一种(稍微)更安全的Package->method写法。
这在文档中有答案。How does Perl parse unquoted bare words?也是相关的。
Foo::等同于"Foo",除了它还检查命名空间Foo是否存在。
Foo也意味着"Foo",但只有当它不意味着其他任何东西时。当它在->之前时,它不受约束,但在这里Foo没有什么特别之处。因此,如果你有一个名为Foo的sub,它将调用该sub。如果你有一个名为Foo的常量,它将被使用。
总的来说,

  • Foo::->method始终表示"Foo"->method
  • Foo->method通常表示"Foo"->method
  • Foo->method也可以表示Foo()->method

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

  • 通过使用Foo::,可以避免意外调用sub(包括常量)。

在实践中,这种情况发生的可能性非常小。人们希望在测试中会发现这种情况。但考虑到这种情况的罕见性,如果它发生的话,可能会令人困惑。

  • 通过使用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 ...

而不是

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

我说更好了吗?我觉得那更吵了。

相关问题