2015-11-18 5 views
9

La mia prova è questa:Qualcuno può spiegare perché Perl si comporta in questo modo (scope variabile)?

use strict; 
use warnings; 

func(); 
my $string = 'string'; 
func(); 

sub func { 
    print $string, "\n"; 
} 

E il risultato è:

Use of uninitialized value $string in print at test.pl line 10. 

string 

Perl ci permette di chiamare una funzione prima che sia stato definito. Tuttavia, quando la funzione utilizza una variabile dichiarata solo dopo la chiamata alla funzione, la variabile sembra non definita. Questo comportamento è documentato da qualche parte? Grazie!

+3

* Sempre * 'usare rigorosamente; usa gli avvertimenti; '! – Biffen

+0

Oh ya In realtà ho questi pragmi nel mio file di test. Lo modifico Grazie. – darkgrin

risposta

12

Il comportamento di my è documentato in perlsub - si riduce a questo - perl sa $string è portata - perché il my dice così.

Il mio operatore dichiara le variabili elencate da lessicalmente confinati al blocco racchiude, condizionale (se/meno/elsif/altro), loop (per/foreach/mentre/fino a/continua), subroutine, eval, o do/require/use'd file.

Significa che è "in ambito" dal punto in cui è "visto" prima della parentesi di chiusura del "blocco" corrente. (O nel tuo esempio - la fine del codice)

Tuttavia - nell'esempio myanche assegna un valore.

Questo processo di scoping avviene in fase di compilazione - dove perl controlla dove è valido utilizzare $string oppure no. (Grazie a strict). Tuttavia, non può sapere quale fosse il valore, poiché ciò potrebbe cambiare durante l'esecuzione del codice. (E non è banale per analizzare)

Quindi, se si esegue questa operazione potrebbe essere un po 'più chiaro quello che sta succedendo:

#!/usr/bin/env perl 
use strict; 
use warnings; 

my $string; #undefined 
func(); 
$string = 'string'; 
func(); 

sub func { 
    print $string, "\n"; 
} 

$string è portata in entrambi i casi - perché il my accaduto al momento della compilazione - prima che la subroutine sia stata chiamata - ma non ha un valore impostato oltre il valore predefinito di undef prima della prima chiamata.

Nota questo contrasta con:

#!/usr/bin/env perl 
use strict; 
use warnings; 

sub func { 
    print $string, "\n"; 
} 

my $string; #undefined 
func(); 
$string = 'string'; 
func(); 

Quali errori perché quando il sub è dichiarata, $string non è nel campo di applicazione.

4

Prima di tutto, considererei questo comportamento non definito poiché salta l'esecuzione di my come my $x if $cond;.

Detto questo, il comportamento è attualmente coerente e prevedibile. E in questo caso, si comporta esattamente come previsto se l'ottimizzazione che ha giustificato l'avviso di comportamento non definito non è stata interrotta.


Al momento della compilazione, my ha l'effetto di dichiarare e allocare la variabile [1]. Gli scalari sono inizializzati su undef una volta creati. Le matrici e gli hash vengono creati vuoti.

my $string è stato rilevato dal compilatore, quindi la variabile è stata creata. Ma poiché non hai ancora eseguito il compito, ha ancora il suo valore predefinito (indefinito) durante la prima chiamata a func.

Questo modello consente di catturare le variabili mediante chiusure.

Esempio 1:

{ 
    my $x = "abc"; 
    sub foo { $x } # Named subs capture at compile-time. 
} 

say foo(); # abc, even though $x fell out of scope before foo was called. 

Esempio 2:

sub make_closure { 
    my ($x) = @_; 
    return sub { $x }; # Anon subs capture at run-time. 
} 

my $foo = make_closure("foo"); 
my $bar = make_closure("bar"); 

say $foo->(); # foo 
say $bar->(); # bar 

  1. L'assegnazione è eventualmente differito fino viene effettivamente utilizzata la variabile.
+0

Non seguo. Esecuzione di 'perl -MDevel :: Peek -e'mysub(); il mio $ foo; sub mysub {Dump ($ pippo)} ''mostra' $ pippo' con il flag PADMY, mentre 'perl -MDevel :: Peek -e'mysub(); sub mysub {Dump ($ foo)} ''(ovviamente) no. Non ne so molto di perlguts, quindi potrei essere lontano, ma sembra che 'my' non venga saltato. Potresti spiegare di più? – ThisSuitIsBlackNot

+0

@ThisSuitIsBlackNot, È un comportamento indefinito usare un vassistole lessicale prima di ESEGUIRE il 'mio' che lo dichiara *. La sua ESECUZIONE è arrivata dopo la prima chiamata a 'func()' nel codice dell'OP. Pertanto, il suo programma si basa su un comportamento indefinito. Hai semplicemente dimostrato che 'my' ha un effetto in fase di compilazione, come ho affermato. (* Queste non sono le parole usate dai documenti. Questa è la mia comprensione dei documenti poco chiari.) – ikegami