Я слышал, что люди не должны использовать &
для вызова Perl subs, i.e:
function($a,$b,...);
# opposed to
&function($a,$b,...);
Я знаю, что список аргументов становится необязательным, но в каких случаях целесообразно использовать &
и случаи, когда вы его абсолютно не используете?
Также как здесь происходит увеличение производительности, если вы опускаете &
?
IMO, единственный раз, когда есть причина использовать &
, это если вы получаете или вызываете coderef, например:
sub foo() {
print "hi\n";
}
my $x = \&foo;
&$x();
Основное время, которое вы можете использовать, которое вы абсолютно не должны в большинстве случаев, - это вызов подпрограммы, у которой есть прототип, который задает поведение по умолчанию, отличное от стандартного. Я имею в виду, что некоторые прототипы позволяют переинтерпретировать список аргументов, например, преобразование спецификаций @array
и %hash
в ссылки. Таким образом, sub будет ожидать, что эти переинтерпретации произойдут, и если вы не зайдете на любую длину, необходимую для имитации их вручную, sub получит входные данные, сильно отличающиеся от ожидаемых.
Я думаю, что в основном люди пытаются сказать вам, что вы все еще пишете в стиле Perl 4, и теперь у нас есть намного более чистая и приятная вещь под названием Perl 5.
Что касается производительности, существуют различные способы, которыми Perl оптимизирует подзаголовки, которые &
проигрывает, причем одним из основных является вложение констант.
Существует также одно обстоятельство, когда использование &
обеспечивает преимущество в производительности: если вы переадресовываете подзаголовок с помощью foo(@_)
. Использование &foo
бесконечно быстрее, чем foo(@_)
. Я бы не рекомендовал его, если вы окончательно не обнаружили путем профилирования, что вам нужна эта микро-оптимизация.
Я часто злоупотребляю &
, но в основном потому, что я делаю странные вещи интерфейса. Если вам не нужна одна из этих ситуаций, не используйте &
. Большинство из них - это просто доступ к определению подпрограммы, а не вызов подпрограммы. Все это в perlsub.
Взятие ссылки на именованную подпрограмму. Вероятно, это единственная распространенная ситуация для большинства Perlers:
my $sub = \&foo;
Аналогично, присваивая typeglob, который позволяет вам вызвать подпрограмму с другим именем:
*bar = \&foo;
Проверка того, что подпрограмма определена, как вы можете в тестовых наборах:
if( defined &foo ) { ... }
Удаление определения подпрограммы, которое не должно быть общим:
undef &foo;
Предоставление подпрограммы диспетчера, единственной задачей которой является выбор правильной подпрограммы для вызова. Это единственная ситуация, в которой я использую &
для вызова подпрограммы, и когда я ожидаю много раз вызывать диспетчера и выжимать небольшое количество операций из операции:
sub figure_it_out_for_me {
# all of these re-use the current @_
if( ...some condition... ) { &foo }
elsif( ...some other... ) { &bar }
else { &default }
}
Чтобы перейти в другую подпрограмму с использованием текущего стека аргументов (и заменить текущую подпрограмму в стеке вызовов), выполняется непрактичная операция при диспетчеризации, особенно в AUTOLOAD
:
goto ⊂
Вызвать подпрограмму, которую вы назвали после встроенного Perl. &
всегда дает вам пользовательский. Это почему мы учим его в Learning Perlя > . Вы действительно не хотите делать это нормально, но это одна из особенностей &
.
Есть несколько мест, где вы могли бы их использовать, но есть лучшие способы:
Чтобы вызвать подпрограмму с тем же именем, что и встроенный Perl. Просто не имеют подпрограмм с тем же именем, что и встроенный Perl. Проверьте perlfunc, чтобы просмотреть список встроенных имен, которые вы не должны использовать.
Чтобы отключить прототипы. Если вы не знаете, что это значит или почему вы хотите, не используйте &
. Некоторый код черной магии может понадобиться, но в таких случаях вы, вероятно, знаете, что делаете.
Чтобы разыменовать и выполнить ссылку подпрограммы. Просто используйте нотацию ->
.
defined &foo
, кажется, что __PACKAGE__->can('foo')
более «современно»? Я был бы заинтересован во мнениях
can
не сказать вам, если подпрограмма определена. Он сообщает вам, если вызываемая подпрограмма can
заставить вас думать, что она определена, даже если это не так.
Форма & подпрограмма() отключает проверку прототипов. Это может быть или не быть тем, что вы хотите.
http://www.perl.com/doc/manual/html/pod/perlsub.html#Prototypes
Прототипы позволяют указывать числа и типы аргументов подпрограммы и проверять их во время компиляции. Это может обеспечить полезную диагностическую помощь.
Прототипы не применяются к вызовам методов или вызовам, выполненным в старомодном стиле с использованием префикса.
и необходимо указать или разыменовать подпрограмму или ссылку на код
например.
sub foo {
# a subroutine
}
my $subref = \&foo; # take a reference to the subroutine
&$subref(@args); # make a subroutine call using the reference.
my $anon_func = sub { ... }; # anonymous code reference
&$anon_func(); # called like this
Протипы также не применимы к ссылкам подпрограмм.
Форма подпрограммы также используется в так называемой форме magic goto.
Выражение goto &subroutine
заменяет текущий вызывающий контекст вызовом именованной подпрограммы с использованием текущего значения @_.
По сути, вы можете полностью переключить вызов на одну подпрограмму с вызовом названного. Это обычно наблюдается в блоках AUTOLOAD, где может быть сделан запрос отложенной подпрограммы, возможно, с некоторой модификацией к @_, но он полностью смотрит на программу, как если бы это был вызов именованного элемента.
например.
sub AUTOLOAD {
...
push @_, @extra_args; # add more arguments onto the parameter list
goto &subroutine ; # change call another subroutine, as if we were never here
}
}
Потенциально это может быть полезно для устранения хвостового вызова, я полагаю.
Я прочитал аргументы против использования '&', но я почти всегда использую его. Это экономит мне слишком много времени, чтобы не делать этого. Я трачу очень большую часть своего времени кодирования в Perl и ищу, какие части кода вызывают определенную функцию. С ведущим &, я могу найти и найти их мгновенно. Без ведущего &, я получаю инструкции определения функции, комментарии и отладки, обычно увеличивая количество кода, которое я должен проверить, чтобы найти то, что я ищу.
Главное не использовать '&' вы покупаете, вы можете использовать прототипы функций. Но прототипы функций Perl могут создавать ошибки так часто, как они их предотвращают, потому что они возьмут ваш список аргументов и переинтерпретируют его так, как вы не можете ожидать, так что вызов функции больше не пропускает аргументы, которые он буквально говорит, что это делает.
&foo
вместо &foo()
или случайно использовать его на постоянной и подавить постоянную вставку. Этих недостатков недостаточно, чтобы препятствовать этому, если вы решите .
&$x()
самом деле не лучший способ вызвать код ref; вы, вероятно, должны просто разыменовать его, как и любой другой ref: $ x -> ().