2011-09-08 22 views

risposta

35

(sub { ... }) vi darà il puntatore alla funzione quindi è necessario chiamare per riferimento.

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

L'altro metodo semplice, come ha sottolineato Blagovest Buyukliev sarebbe quello di dereference il puntatore a funzione e chiamare che utilizzando gli operatori { }

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

+0

che dovrebbe essere '& {sub {print "Ciao Mondo"}} () '. Senza i paren, è una chiamata molto speciale. – ikegami

+0

così vero ikegami - risolto – zellio

+0

@ikegami: cosa intendi con 'una chiamata molto speciale'? Perché non puoi lasciare le parentesi? –

4

È necessario operatore freccia:

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

Sono infinitamente divertito da trovare modi chiamare le funzioni anonime:

$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 

e, naturalmente, l'ovvio:

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

Non c'è molto bisogno in Perl per chiamare una subroutine anonima in cui è definito. In generale è possibile ottenere qualsiasi tipo di ambito necessario con blocchi nudi. Il caso di un utilizzo che viene in mente è quello di creare una matrice alias:

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

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

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

In caso contrario, si potrebbe solito memorizzare una subroutine anonima in una struttura di variabile o di dati. I seguenti stili di chiamata funzionano sia con una variabile e una dichiarazione sub {...}:

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

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

se avete la rifcodice in uno scalare, si può anche usarlo come un metodo su valori regolari e benedetti.

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], ...) 
+1

'sub {} ->()', 'do {}' e '{}' hanno tutte proprietà differenti. Metterei 'sub {} ->()' più vicino a 'do {}', non '{}'. – ikegami

22

Yay, non mi aspettavo che la gente venisse con così tante possibilità. Ma hai ragione, questo è perl e TIMTOWTDI: +1 per la creatività!

Ma ad essere onesti, io uso quasi un'altra forma di quanto segue:

Il Sintassi di base

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

# ... 

$greet->('asker') 

E 'piuttosto semplice: sub {} restituisce un riferimento a una routine sub, che è possibile memorizzare e passare come qualsiasi altro scalare. È possibile chiamarlo con il dereferenziamento. C'è anche una seconda sintassi per il dereferenziamento: &{ $sub }('asker'), ma personalmente preferisco la sintassi della freccia, perché la trovo più leggibile e si allinea praticamente agli hash di dereferenziamento $hash->{ $key } e agli array $array->[ $index ]. Ulteriori informazioni sui riferimenti sono disponibili in perldoc perlref.

penso che gli altri esempi sono un po 'avanzato, ma perché non dare un'occhiata a loro:

Goto

sub bar {goto $foo}; 
bar; 

vede raramente e molto temuto in questi giorni.Ma almeno è un goto &function, che è considerato meno dannoso degli amici storti: goto LABEL o goto EXPRESSION (sono deprecati dal 5.12 e sollevano un avvertimento). Ci sono in realtà alcune circostanze, quando si desidera utilizzare tale modulo, perché questa non è una normale chiamata di funzione. La funzione di chiamata (bar nell'esempio fornito) non verrà visualizzata nella serie di chiamate. E non si passano i parametri, ma verrà utilizzato l'attuale @_. Date un'occhiata a questo:

use Carp qw(cluck); 

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


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

invisible('real'); 

uscita:

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

E non c'è traccia di una funzione invisibile nella traccia dello stack. Maggiori informazioni su goto in perldoc -f goto.

Metodo Chiamate

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

Se si chiama un metodo su un oggetto, il primo parametro passato a quel metodo sarà l'invocant (di solito un istanza o il nome della classe). Ho già detto che 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 

Nel frammento di sopra sono due chiamate, che non funzioneranno, perché perl cercheranno di trovare un metodo chiamato ask nel pacchetto asker (in realtà avrebbe funzionato se quel codice è stato in detto pacchetto). Ma il terzo succede, perché già dai perl il metodo giusto e non è necessario cercarlo. Come sempre: maggiori informazioni nello perldoc Non riesco a trovare alcuna ragione al momento, per scusare questo nel codice di produzione.

Conclusione

Originariamente non ho intenzione di scrivere più di tanto, ma penso che sia importante avere la soluzione comune all'inizio di una risposta e alcune spiegazioni ai costrutti insolite. Ammetto di essere un po 'egoista qui: ognuno di noi potrebbe finire per mantenere il codice di qualcuno, che ha trovato questa domanda e ha appena copiato l'esempio più in alto.

+3

+1 per coraggio; ogni volta che do il mio tempo per scrivere risposte come questa, vengo raggirato dai camion con downvotes che contengono ... troppo a lungo .. o .. nessuno vuole passare così tanto tempo a leggere questo ... quindi, metterò in questo +1 nel caso in cui venite investiti da un camion. (e chiunque altro lo abbia fatto) – osirisgothra

+1

@osirisgothra grazie per le belle parole. la risposta è di quasi quattro anni - e finora nessun camion :-D –

+2

I programmatori che non possono essere disturbati a leggere sono pigri nel modo sbagliato, non nel modo migliore.Fondamentalmente non sono lontani dal "do my [home] lavoro per me così posso andare [alla spiaggia | casa presto]" folla. –

0

Potrebbe non essere nemmeno necessaria una funzione anonima se si desidera eseguire un blocco di codice e vi è zero o un input. È possibile utilizzare map invece.

Solo per l'effetto collaterale:

map { print 1 } 1; 

Trasforma dati, fare attenzione ad assegnare a un elenco:

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