(sub {
print 1;
})();
sub {
print 1;
}();
Я пробовал разные способы, все неправильно...
(sub {
print 1;
})();
sub {
print 1;
}();
Я пробовал разные способы, все неправильно...
(sub { ... })
предоставит вам указатель на функцию, чтобы вы могли позвонить по ссылке.
(sub { print "Hello world\n" })->();
Другим простым способом, как отметил Благовест Буюклиев, было бы разыменовать указатель на функцию и вызвать это с помощью операторов { }
&{ sub { print "Hello World" }}();
Да, я не ожидал, что вы придумаете такие возможности. Но вы правы, это perl и TIMTOWTDI: +1 для творчества!
Но, честно говоря, я использую чуть-чуть другую форму, чем следующее:
my $greet = sub {
my ( $name ) = @_;
print "Hello $name\n";
};
# ...
$greet->( 'asker' )
Это довольно прямолинейно: sub {}
возвращает ссылку на подпрограмму, которую вы можете хранить и передавать, как и любой другой скаляр. Вы можете назвать это разыменованием. Существует также второй синтаксис разыменования: &{ $sub }( 'asker' )
, но я лично предпочитаю синтаксис стрелки, потому что я считаю его более читаемым и в значительной степени согласуется с хэшами разыменования $hash->{ $key }
и массивами $array->[ $index ]
. Более подробную информацию о ссылках можно найти в perldoc perlref.
Я думаю, что другие приведенные примеры немного продвинуты, но почему бы не взглянуть на них:
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, который нашел этот вопрос и просто скопировал самый верхний пример.
В 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], ...)
Я бесконечно удивлен, найдя способы анонимных функций:
$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->();
Вам нужен оператор стрелки:
(sub { print 1;})->();
Возможно, вам даже не нужна анонимная функция, если вы хотите запустить блок кода и есть нуль или один вход. Вместо этого вы можете использовать map
.
Только для побочного эффекта:
map { print 1 } 1;
Преобразовать данные, позаботьтесь о назначении списку:
my ($data) = map { $_ * $_ } 2;