Как передать анонимные подпрограммы при вызове подпрограммы Perl?

mysub получает ссылку на подпрограмму в качестве первого аргумента.

Могу я просто позвонить mysub(sub{some subroutine body here}) ? т.е. определить анонимную подпрограмму прямо при вызове?

В порядке ли синтаксис (действительно ли передается ссылка на sub)?


person David B    schedule 18.09.2010    source источник
comment
Я попробовал, и это сработало (иначе я бы даже не спрашивал), НО я помню несколько случаев из своей истории, когда я проверял что-то, что я изобрел на Perl, и это, казалось, работало, но позже я обнаружил, что на самом деле это работало только для в конкретных случаях у меня есть яички, и общая идея/синтаксис, который я использовал, был совершенно неверным... :)   -  person David B    schedule 18.09.2010


Ответы (3)


Что произошло, когда вы попробовали это? Это, безусловно, лучший способ проверить, работают ли такие вещи.

Но да, этот синтаксис будет работать нормально.

#!/usr/bin/perl

use strict;
use warnings;

sub run_sub {
  shift->();
}

run_sub( sub { print "hello\n"; } );
person Dave Cross    schedule 18.09.2010

Поскольку передача ссылок на подпрограммы другим подпрограммам является довольно распространенным шаблоном, в Perl даже есть несколько синтаксических приемов, которые делают его еще более плавным:

sub function1 {          # normal declaration, implicit `(@)` prototype
    my $code = shift;
    $code->(@_);
}

sub function2 (&@) {     # prototyped declaration
    my $code = shift;
    $code->(@_);
}

function1 должен вызываться как: function1 sub{...}, any_other_args

function2 имеет прототип (&@), который указывает компилятору наложить контекст подпрограммы на первый аргумент (а затем принять любое количество дополнительных аргументов).

Таким образом, вы можете назвать его как function2 {...} any_other_args, что отражает способ, которым встроенные функции более высокого порядка, такие как map, grep и sort, берут свои блоки кода. Обратите внимание, что после блока кода запятая не ставится, как и в случае с bultins.

Дополнительную информацию о прототипах можно найти здесь: http://perldoc.perl.org/perlsub.html#Prototypes

Имейте в виду, что прототипы Perl НЕ предназначены для проверки аргументов, они являются подсказками для компилятора, которые позволяют вам писать подпрограммы, которые ведут себя как встроенные.

person Eric Strom    schedule 18.09.2010

В качестве альтернативы (к ответу @davorg) вы можете использовать:

sub run_sub
{
    my($funcref) = @_;
    &$funcref();
}

Конечно, более подробный; также немного яснее, я думаю. Но это Perl — TMTOWTDI!

person Jonathan Leffler    schedule 18.09.2010
comment
$funcref->() немного более современный Perlish, но я думаю, что они абсолютно идентичны. - person Ether; 18.09.2010
comment
Они не идентичны. Синтаксис &foo (или &$foo в данном случае coderef) может обойти прототипы. - person Sdaz MacSkibbons; 18.09.2010
comment
@Simon И &$foo, и $foo->() будут обходить прототипы. Из perldoc.perl.org/perlsub.html#Prototypes: прототипы не влияют на ссылки на подпрограммы, такие как \&foo, или косвенные вызовы подпрограмм, такие как &{$subref} или $subref->(). - person FMc; 18.09.2010