Когда мне следует использовать & для вызова подпрограммы Perl? - PullRequest
47 голосов
/ 28 августа 2009

Я слышал, что люди не должны использовать & для вызова подпрограмм Perl, т. Е.

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

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

Кроме того, как здесь увеличивается производительность, если пропустить &?

Ответы [ 4 ]

52 голосов
/ 28 августа 2009

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

  1. Получение ссылки на именованную подпрограмму. Это, вероятно, единственная распространенная ситуация для большинства Perlers:

     my $sub = \&foo;
    
  2. Аналогично, присваивание типоглобу, который позволяет вам вызывать подпрограмму с другим именем:

     *bar = \&foo;
    
  3. Проверка того, что подпрограмма определена, как вы могли бы в тестовых наборах:

     if( defined &foo ) { ... }
    
  4. Удаление определения подпрограммы, которое не должно быть общим:

     undef &foo;
    
  5. Предоставление диспетчерской подпрограммы, единственной задачей которой является выбор подходящей подпрограммы для вызова. Это единственная ситуация, в которой я использую от & до вызова подпрограммы, и когда я ожидаю многократного вызова диспетчера и мне нужно немного снизить производительность из операции:

     sub figure_it_out_for_me {
        # all of these re-use the current @_
          if( ...some condition... ) { &foo     } 
       elsif( ...some other...     ) { &bar     }
       else                          { &default }
       }
    
  6. Для перехода в другую подпрограмму с использованием текущего стека аргументов (и замены текущей подпрограммы в стеке вызовов), операция unrare при диспетчеризации, особенно в AUTOLOAD:

     goto ⊂
    
  7. Вызовите подпрограмму, которую вы назвали в честь встроенного в Perl. & всегда дает вам определенный пользователем. Вот почему мы учим этому в Изучение Perl . Вы действительно не хотите делать это нормально, но это одна из особенностей &.

Есть несколько мест, где вы можете их использовать, но есть и лучшие способы:

  1. Для вызова подпрограммы с тем же именем, что и встроенный в Perl. Просто не используйте подпрограммы с тем же именем, что и встроенный в Perl. Проверьте perlfunc , чтобы увидеть список встроенных имен, которые вы не должны использовать.

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

  3. Для разыменования и выполнения ссылки на подпрограмму. Просто используйте обозначение ->.

36 голосов
/ 28 августа 2009

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

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

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

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

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

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

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

17 голосов
/ 28 августа 2009

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

http://www.perl.com/doc/manual/html/pod/perlsub.html#Prototypes

Прототипы позволяют вам указывать номера и типы аргументов подпрограммы и проверять их во время компиляции. Это может оказать полезную диагностическую помощь.

Прототипы не применяются к вызовам методов или вызовам, сделанным в старом стиле с использованием префикса &.

Символ & необходим для ссылки или разыменования подпрограммы или ссылки на код

1012 *, например *

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 голос
/ 11 марта 2015

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

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

...