2010-09-18 2 views
2

mysub получает в качестве первого аргумента ссылку подпрограммы.Как передать анонимные подпрограммы при вызове подпрограммы Perl?

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

Является синтаксисом ОК (действительно ли это ссылка на sub, которая передается)?

+4

Вы попробовали? –

+2

Я пробовал, и это сработало (в противном случае я бы даже не спросил), НО я вспоминаю несколько примеров из моей истории, когда я тестировал что-то, что я «придумал» на Perl, и это, казалось, сработало, но позже я обнаружил, что он действительно работал только для конкретных случаев у меня есть тестеры, а общая идея/синтаксис, который я использовал, была просто неправильной ... :) –

ответ

8

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

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

#!/usr/bin/perl 

use strict; 
use warnings; 

sub run_sub { 
    shift->(); 
} 

run_sub(sub { print "hello\n"; }); 
2

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

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

Подробней, конечно; тоже немного яснее, думаю. Но это Perl - TMTOWTDI!

+0

'$ funcref ->()' немного более современный Perlish, но я думаю, что они абсолютно идентичны. – Ether

+1

Они не идентичны. Синтаксис '& foo' (или' & $ foo' в этом случае coderef) может обойти прототипы. –

+1

@Simon Оба '& $ foo' и' $ foo ->() 'будут обходить прототипы. От http://perldoc.perl.org/perlsub.html#Prototypes: «прототипы не влияют на ссылки подпрограмм типа' \ & foo' или на вызовы косвенной подпрограммы типа '& {$ subref}' или '$ subref->() '«. – FMc

5

Поскольку передавая ссылки подпрограммы других подпрограмм является довольно распространенным узором, 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 принимать их кодовые блоки. Обратите внимание, что после блока кода нет запятой, точно так же, как с бултинами.

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

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

Смежные вопросы