Обозначение Perl "Package::->method()" (двоеточие-двоеточие-стрелка)
Я читал документацию по
attributes
модуль и наткнулся на нотацию вызова метода, которую я никогда не видел:
use attributes ();
attributes::->import(__PACKAGE__, \$x, 'Bent');
В документе не предоставлено объяснение этого синтаксиса.
При расследовании это кажется эквивалентным и'Package'->method()
.
Это также кажется эквивалентнымPackage::method('Package')
, при условии, что метод не наследуется.
Вопрос 0: Есть ли практическая причина использования обозначений?
Изменить: я обнаружил, что если у вас есть константа с тем же именем, что и пакет,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::' относится к несуществующему пакету», но все равно выполнит его , что еще больше меня смущает.
Еще более странно, добавив строкуFoo::method();
передFoo::->method()
строка избавляется от предупреждения «Bareword» .
Вопрос 1: Может кто-нибудь объяснить, что происходит?
Для потомков это Perl v5.38.0.
1 ответ
Package::->method
это (немного) более безопасный способ записиPackage->method
.
На это отвечает документация . Как Perl анализирует слова без кавычек?также актуально.
эквивалентно , за исключением того, что он также проверяет, существует ли пространство имен.
также значит"Foo"
, но только если это не означает ничего другого. Он освобожден от ограничений, когда раньше->
, но в остальном здесь нет ничего особенного. Итак, если у вас есть подпрограмма с именем , и она вызовет эту подпрограмму. Если у вас есть константа с именемFoo
, он будет использован.
В итоге,
-
Foo::->method
всегда значит. - обычно означает
"Foo"->method
. - также может означать.
Отсюда мы выводим следующие причины использования:
Используя , вы избежите случайного вызова подпрограммы. (Сюда входят константы.)
На практике вероятность того, что это произойдет, невероятно мала. И мы надеемся, что это будет обнаружено в ходе тестирования. Но, учитывая редкость подобных явлений, если бы это когда-либо произошло, это могло бы сбить с толку.
Используя , вы сигнализируете, что это не дополнительный вызов.
Но это уже предположение, когда вы видите что-то в форме
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 ...
Я сказал лучше? Для меня это просто более шумно.