2011-01-12 19 views
17

Una delle prime cose che cerco di imparare in un linguaggio di programmazione non familiare è come gestisce le chiusure. La loro semantica è spesso intrecciata con il modo in cui la lingua gestisce gli ambiti e vari altri aspetti delicati, quindi la loro comprensione rivela molti altri aspetti della lingua. Inoltre, le chiusure sono un costrutto molto potente e spesso riducono il numero di piastre che devo digitare. Così ho dovuto vedermela con chiusure perl e sono incappato in un po 'Gotcha:

my @closures; 
foreach (1..3) { 
    # create some closures 
    push @closures, sub { say "I will remember $_"; }; 
} 
foreach (@closures) { 
    # call the closures to see what they remember 
    # the result is not obvious 
    &{$_}(); 
} 

Quando ho scritto il codice di cui sopra mi aspettavo di vedere

I will remember 1 
I will remember 2 
I will remember 3 

ma invece ho ottenuto I will remember CODE(0x986c1f0).

L'esperimento precedente ha rivelato che $_ è molto dipendente dal contesto e se appare in una chiusura, il suo valore non viene fissato al momento della creazione della chiusura. Si comporta più come un riferimento. Quali altri trucchi devo sapere quando creo chiusure in perl?

risposta

25

Le chiusure si chiudono solo su variabili lessicali; $_ è normalmente una variabile globale. In 5.10 e versioni successive, si può dire my $_; per avere un valore lessicale in un determinato ambito (sebbene in 5.18 questo sia stato dichiarato retroattivamente come sperimentale e soggetto a modifiche, quindi è meglio usare qualche altro nome di variabile).

Questo produce l'output che vi aspettavate:

use strict; 
use warnings; 
use 5.010; 
my @closures; 
foreach my $_ (1..3) { 
    # create some closures 
    push @closures, sub { say "I will remember $_"; }; 
} 
foreach (@closures) { 
    # call the closures to see what they remember 
    # the result is not obvious 
    &{$_}(); 
} 
+2

Ma questo è praticamente lo stesso di usare 'foreach my $ num ...'. – davidk01

+1

Quindi se chiudono solo su variabili lessicali cosa succede ad altri tipi di variabili? La chiusura usa il valore disponibile durante il sito di chiamata come fa per '$ _'? – davidk01

+1

@ davidk01: come in qualsiasi altro linguaggio di programmazione che consente le variabili globali, le chiusure si chiudono effettivamente su quella variabile come normale. Hai appena dimenticato che è globale e può quindi cambiare quando un altro codice imposta il suo valore su qualcos'altro (come il sottotitolo anonimo stesso quando viene chiamato). – slebetman

3

$ _ è una variabile globale e non dovrebbe essere utilizzato in chiusura. Prima di utilizzarlo, assegnarlo a una variabile con scope lessicale come mostrato in bewlow. Questo produrrà previsto o/p.

#!/usr/bin/perl -w 

use strict; 
my @closures; 


foreach (1..3) { 
    my $var = $_; 
    push @closures, sub { print "I will remember $var"; }; 
} 

foreach (@closures) { 
    $_->(); 
    print "\n"; 
}