Символ &
обычно не используется с вызовами функций в современном Perl по двум причинам. Во-первых, это в значительной степени избыточно, так как Perl будет рассматривать функцию, которая выглядит как функция (за которой следует парамен). Во-вторых, существует большая разница между способами выполнения &function()
и &function
, что может сбивать с толку менее опытных программистов на Perl. В первом случае функция вызывается без аргументов. Во втором случае функция вызывается с текущим значением @_
(и она может даже вносить изменения в список аргументов, что будет видно в последующих операторах в этой области:
sub print_and_remove_first_arg {print 'first arg: ', shift, "\n"}
sub test {
&print_and_remove_first_arg;
print "remaining args: @_\n";
}
test 1, 2, 3;
печать
first arg: 1
remaining args: 2 3
Таким образом, в конечном итоге, использование &
для каждого вызова функции приводит к сокрытию нескольких вызовов &function;
, которые могут привести к трудным поискам ошибок. Кроме того, использование символа &
предотвращает запоминание прототипов функций, что может быть полезно в некоторых случаях (если вы знаете, что делаете), но также может привести к трудным поискам ошибок. В конечном итоге, &
является мощным модификатором поведения функций, и его следует использовать только тогда, когда это поведение желательно.
Прототипы похожи, и их использование должно быть ограничено в современном Perl. Что следует четко указать, так это то, что прототипы в Perl НЕ являются сигнатурами функций. Они являются подсказками для компилятора, которые говорят ему анализировать вызовы этих функций аналогично встроенным функциям. То есть каждый из символов в прототипе указывает компилятору наложить этот тип контекста на аргумент. Эта функциональность может быть очень полезна при определении функций, которые ведут себя как map
или push
или keys
, которые все обрабатывают свой первый аргумент иначе, чем стандартный оператор списка.
sub my_map (&@) {...} # first arg is either a block or explicit code reference
my @ret = my_map {some_function($_)} 1 .. 10;
Причина sub ($$) {...}
и подобного использования прототипов не приветствуется, потому что 9 раз из 10 автор имеет в виду «я хочу два аргумента», а не «я хочу два аргумента каждый со скалярным контекстом, наложенным на сайт вызова». Первое утверждение лучше написано:
use Carp;
sub needs2 {
@_ == 2 or croak 'needs2 takes 2 arguments';
...
}
, что позволило бы следующему стилю вызова работать как положено:
my @array = (2, 4);
needs2 @array;
Подводя итог, можно сказать, что и прототип &
sigil и функция являются полезными и мощными инструментами, но их следует использовать только тогда, когда требуется эта функциональность. Их избыточное использование (или неправильное использование в качестве проверки аргументов) ведет к непреднамеренному поведению и затрудняет поиск ошибок.