Когда я должен использовать & для вызова подпрограммы Perl?

45

Я слышал, что люди не должны использовать & для вызова Perl subs, i.e:

function($a,$b,...);
# opposed to
&function($a,$b,...);

Я знаю, что список аргументов становится необязательным, но в каких случаях целесообразно использовать & и случаи, когда вы его абсолютно не используете?

Также как здесь происходит увеличение производительности, если вы опускаете &?

Теги:
subroutine

4 ответа

33
Лучший ответ

IMO, единственный раз, когда есть причина использовать &, это если вы получаете или вызываете coderef, например:

sub foo() {
    print "hi\n";
}

my $x = \&foo;
&$x();

Основное время, которое вы можете использовать, которое вы абсолютно не должны в большинстве случаев, - это вызов подпрограммы, у которой есть прототип, который задает поведение по умолчанию, отличное от стандартного. Я имею в виду, что некоторые прототипы позволяют переинтерпретировать список аргументов, например, преобразование спецификаций @array и %hash в ссылки. Таким образом, sub будет ожидать, что эти переинтерпретации произойдут, и если вы не зайдете на любую длину, необходимую для имитации их вручную, sub получит входные данные, сильно отличающиеся от ожидаемых.

Я думаю, что в основном люди пытаются сказать вам, что вы все еще пишете в стиле Perl 4, и теперь у нас есть намного более чистая и приятная вещь под названием Perl 5.

Что касается производительности, существуют различные способы, которыми Perl оптимизирует подзаголовки, которые & проигрывает, причем одним из основных является вложение констант.

Существует также одно обстоятельство, когда использование & обеспечивает преимущество в производительности: если вы переадресовываете подзаголовок с помощью foo(@_). Использование &foo бесконечно быстрее, чем foo(@_). Я бы не рекомендовал его, если вы окончательно не обнаружили путем профилирования, что вам нужна эта микро-оптимизация.

  • 0
    Не могли бы вы рассказать подробнее о «поведении вызова не по умолчанию»?
  • 24
    За исключением того, что &$x() самом деле не лучший способ вызвать код ref; вы, вероятно, должны просто разыменовать его, как и любой другой ref: $ x -> ().
Показать ещё 3 комментария
47

Я часто злоупотребляю &, но в основном потому, что я делаю странные вещи интерфейса. Если вам не нужна одна из этих ситуаций, не используйте &. Большинство из них - это просто доступ к определению подпрограммы, а не вызов подпрограммы. Все это в 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, чтобы просмотреть список встроенных имен, которые вы не должны использовать.

  • Чтобы отключить прототипы. Если вы не знаете, что это значит или почему вы хотите, не используйте &. Некоторый код черной магии может понадобиться, но в таких случаях вы, вероятно, знаете, что делаете.

  • Чтобы разыменовать и выполнить ссылку подпрограммы. Просто используйте нотацию ->.

  • 0
    Вы действительно хотите сделать defined &foo , кажется, что __PACKAGE__->can('foo') более «современно»? Я был бы заинтересован во мнениях
  • 2
    can не сказать вам, если подпрограмма определена. Он сообщает вам, если вызываемая подпрограмма can заставить вас думать, что она определена, даже если это не так.
Показать ещё 1 комментарий
16

Форма & подпрограмма() отключает проверку прототипов. Это может быть или не быть тем, что вы хотите.

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
}

}

Потенциально это может быть полезно для устранения хвостового вызова, я полагаю.

см. подробное объяснение этого метода здесь

1

Я прочитал аргументы против использования '&', но я почти всегда использую его. Это экономит мне слишком много времени, чтобы не делать этого. Я трачу очень большую часть своего времени кодирования в Perl и ищу, какие части кода вызывают определенную функцию. С ведущим &, я могу найти и найти их мгновенно. Без ведущего &, я получаю инструкции определения функции, комментарии и отладки, обычно увеличивая количество кода, которое я должен проверить, чтобы найти то, что я ищу.

Главное не использовать '&' вы покупаете, вы можете использовать прототипы функций. Но прототипы функций Perl могут создавать ошибки так часто, как они их предотвращают, потому что они возьмут ваш список аргументов и переинтерпретируют его так, как вы не можете ожидать, так что вызов функции больше не пропускает аргументы, которые он буквально говорит, что это делает.

  • 2
    согласовано. в кодовой базе, которая использует его последовательно, и может быть полезной. единственные недостатки не позволяют использовать прототипы (если вы можете назвать это недостатком) или возможность случайно сказать &foo вместо &foo() или случайно использовать его на постоянной и подавить постоянную вставку. Этих недостатков недостаточно, чтобы препятствовать этому, если вы решите .

Ещё вопросы

Сообщество Overcoder
Наверх
Меню