Да, я не ожидал, что вы, ребята, придумаете столько возможностей. Но вы правы, это 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;
Редко видел и очень боялся в эти дни. Но по крайней мере это 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;
Если вы вызываете метод для объекта, первым параметром, переданным этому методу, будет инвокант (обычно это экземпляр или имя класса). Я уже говорил, что 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's 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 . Сейчас я не могу найти никакой причины, чтобы оправдать это в рабочем коде.
Заключение
Первоначально я не собирался писать так много, но я думаю, что важно иметь общее решение в начале ответа и некоторые объяснения необычных конструкций. Я признаю, что здесь немного эгоистично: каждый из нас может в конечном итоге поддерживать чей-то код, который нашел этот вопрос и просто скопировал самый верхний пример.