Как это вызовет подпрограмму в модуле Perl?

Недавно я увидел некоторый код Perl, который меня смутил. Я достал все лишние детали, чтобы посмотреть, как он работает, но я до сих пор не понимаю, почему он работает.

В принципе, я создал этот фиктивный "модуль" (TTT.pm):

use strict;
use warnings;

package TTT;
sub new {
    my $class = shift;
    return bless {'Test' => 'Test'}, $class;
}

sub acquire {
    my $tt = new TTT();
    return $tt;
}
1;

Затем я создал этот script для использования модуля (ttt.pl):

#!/usr/bin/perl
use strict;
use warnings;

use TTT;
our $VERSION = 1;

my $tt = acquire TTT;
print $tt->{Test};

Линия, которая меня смущает, которая, как я думал, не сработает, такова:

my $tt = acquire TTT;

Я думал, что это не сработает, так как "приобретать" юг никогда не экспортировался. Но это действительно работает. Я был смущен "TTT" после вызова для приобретения, поэтому я удалил его, оставив строку следующим образом:

my $tt = acquire;

И он жаловался на одно слово, как я думал. Я добавил parens, вот так:

my $tt = acquire();

И он жаловался, что не было main::acquire, как я думал, это будет.

Я использую подпрограммы, доступные для объекта, или подпрограммы, экспортируемые, но я никогда не видел, чтобы подпрограмма вызывалась с именем пакета в конце. Я даже не знаю, как искать это в Google.

Итак, мой вопрос: как добавить имя пакета после вызова подпрограммы? Я никогда не видел ничего подобного раньше, и это, вероятно, не очень хорошая практика, но может кто-то объяснить, что делает Perl?

Спасибо!

Ответ 1

Вы используете синтаксис косвенных объектов, который позволяет Perl (но в современном коде не рекомендуется). В принципе, если имя не предопределено, оно может быть помещено перед объектом (или именем класса), разделенным пробелом.

Таким образом, строка acquire TTT означает TTT->acquire. Если у вас на самом деле была подпрограмма с именем acquire в области видимости, она вместо этого была бы интерпретирована как aquire(TTT), что может привести к двусмысленности (отсюда почему она не поощряется).

Вы также должны обновить строку new TTT(); в методе, чтобы прочитать TTT->new;

Ответ 2

Это косвенный синтаксис объекта для вызовов методов, который позволяет помещать имя метода перед именем объекта.

Как видно из документации, ее лучше избегать, поскольку она громоздка и может быть непредсказуемой, например, если есть импортированная или определенная подпрограмма с именем acquire - но она была более распространенной, чем сегодня, и поэтому вы найдете его довольно часто в старом коде и документах.