Подтвердить что ты не робот

Как запустить анонимную функцию в Perl?

(sub {
print 1;
})();



sub {
print 1;
}();

Я пробовал разные способы, все неправильно...

4b9b3361

Ответ 1

(sub { ... }) предоставит вам указатель на функцию, чтобы вы могли позвонить по ссылке.

(sub { print "Hello world\n" })->();

Другим простым способом, как отметил Благовест Буюклиев, было бы разыменовать указатель на функцию и вызвать это с помощью операторов { }

&{ sub { print "Hello World" }}();

Ответ 2

Да, я не ожидал, что вы придумаете такие возможности. Но вы правы, это perl и TIMTOWTDI: +1 для творчества!

Но, честно говоря, я использую чуть-чуть другую форму, чем следующее:

Основной синтаксис

my $greet = sub {
    my ( $name ) = @_;
    print "Hello $name\n";
};

# ...

$greet->( 'asker' )

Это довольно прямолинейно: sub {} возвращает ссылку на подпрограмму, которую вы можете хранить и передавать, как и любой другой скаляр. Вы можете назвать это разыменованием. Существует также второй синтаксис разыменования: &{ $sub }( 'asker' ), но я лично предпочитаю синтаксис стрелки, потому что я считаю его более читаемым и в значительной степени согласуется с хэшами разыменования $hash->{ $key } и массивами $array->[ $index ]. Более подробную информацию о ссылках можно найти в perldoc perlref.

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

Goto

sub bar {goto $foo};
bar;

Редко видел и много опасался в эти дни. Но по крайней мере это a goto &function, который считается менее вредным, чем его кривые друзья: goto LABEL или goto EXPRESSION (они устарели с 5.12 и поднимают предупреждение). Фактически есть некоторые обстоятельства, когда вы хотите использовать эту форму, потому что это не обычный вызов функции. Вызывающая функция (bar в данном примере) не будет отображаться в стеке вызова. И вы не передадите свои параметры, но будет использоваться текущий @_. Посмотрите на это:

use Carp qw( cluck );

my $cluck = sub {
    my ( $message ) = @_;
    cluck $message . "\n";
};


sub invisible {
    @_ = ( 'fake' );
    goto $cluck;
}

invisible( 'real' );

Вывод:

fake at bar.pl line 5
    main::__ANON__('fake') called at bar.pl line 14

И нет никакой намека на невидимую функцию в трассировке стека. Дополнительная информация о goto в perldoc -f goto.

Вызов методов

''->$foo;
# or
undef->$foo;

Если вы вызываете метод для объекта, первым параметром, переданным этому методу, будет invocant (обычно это экземпляр или имя класса). Я уже сказал, что TIMTOWTCallAFunction?

# this is just a normal named sub
sub ask {
    my ( $name, $question ) = @_;
    print "$question, $name?\n";
};

my $ask = \&ask; # lets take a reference to that sub 

my $question = "What up";

'asker'->ask( $question ); # 1: doesn't work

my $meth_name = 'ask';
'asker'->$meth_name( $question ); # 2: doesn't work either

'asker'->$ask( $question ); # 1: this works

В приведенном выше фрагменте есть два вызова, которые не будут работать, потому что perl попытается найти метод с именем ask в пакете asker (на самом деле он работал бы, если бы этот код был в указанном пакете). Но третий успешно, потому что вы уже даете perl правильный метод, и ему не нужно его искать. Как всегда: больше информации в perldoc Я не могу сейчас найти какую-либо причину, чтобы оправдать это в производственном коде.

Заключение

Изначально я не собирался писать так много, но я думаю, что важно иметь общее решение в начале ответа и некоторые пояснения к необычным конструкциям. Я признаю себя таким эгоистичным: каждый из нас может закончить код someones, который нашел этот вопрос и просто скопировал самый верхний пример.

Ответ 3

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

my $alias = sub {\@_}->(my ($x, $y, $z));

$x = $z = 0;
$y = 1;

print "@$alias"; # '0 1 0'

В противном случае вы обычно должны хранить анонимную подпрограмму в переменной или структуре данных. Следующие вызывающие стили работают как с объявлением переменной, так и с sub {...}:

dereference arrow:  sub {...}->(args)  or  $code->(args)

dereference sigil:  &{sub {...}}(args) or &$code(args)

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

my $method = sub {...};

$obj->$method           # same as $method->($obj)
$obj->$method(...)      # $method->($obj, ...)

[1, 2, 3]->$method      # $method->([1, 2, 3])
[1, 2, 3]->$method(...) # $method->([1, 2, 3], ...)

Ответ 4

Я бесконечно удивлен, найдя способы анонимных функций:

$foo = sub {say 1};

sub bar {goto $foo};
bar;

''->$foo; # technically a method, along with the lovely:

undef->$foo;

() = sort $foo 1,1; # if you have only two arguments

и, конечно, очевидное:

&$foo();
$foo->();

Ответ 5

Вам нужен оператор стрелки:

(sub { print 1;})->();

Ответ 6

Возможно, вам даже не нужна анонимная функция, если вы хотите запустить блок кода и есть нуль или один вход. Вместо этого вы можете использовать map.

Только для побочного эффекта:

map { print 1 } 1;

Преобразовать данные, позаботьтесь о назначении списку:

my ($data) = map { $_ * $_ } 2;