Обозначение 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 ...
    

    Я сказал лучше? Для меня это просто более шумно.

Другие вопросы по тегам