2010-02-25 12 views
6

Perché il seguente frammento funziona? E quale male potrebbe essere possibile usando questo? Ma seriamente, c'è qualche ragione, il codice in ${} viene valutato e poi usato come riferimento scalare?

use strict; 
no strict 'refs'; 

our $message = "Hello world!"; 
print "${ lc 'MESSAGE' }\n";
+4

Hai esplicitamente dichiarato che volevi utilizzare i riferimenti simbolici e 'perl' ha fatto la tua offerta. –

+0

Ecco come funziona il dereferenziamento. Potresti trovare utile: http://perlmonks.org/?node=References+quick+reference – ysth

risposta

2

OK, unless you use symbolic references. Supponiamo che il seguente codice:

my %messages = (hello => "Hello world!", bye => "Bye-bye, world!"); 
sub get_message_ref { return \$messages{$_[0]} }; # returns scalarref 
print "${ get_message_ref('bye') }\n"; 

d'accordo, la sua utilità non è evidente con scalarrefs, ma è molto utile con arrayrefs.

print "keys: @{[keys %messages]}\n"; 
+0

http://stackoverflow.com/tags/perl+symbolic-reference –

+0

Non mi piace a seconda dell'impostazione di $ "', quindi lo userei solo per un'espressione che restituisce un singolo scalare e per quello, '" $ {\ expr} "' è buono come '" @ {[expr]} "', se meno simmetrico. – ysth

+0

@ysth Ok, mi hai preso. Sono d'accordo con te.Ma quando stai scrivendo una sceneggiatura di una volta, va tutto bene. – codeholic

4

Dal "Using References" section of the perlref documentation:

Ovunque ci si mette un identificatore (o catena di identificatori) come parte di un nome di variabile o subroutine, è possibile sostituire l'identificatore con un blocco che restituisce un riferimento del tipo corretto. In altre parole, gli esempi precedenti potrebbero essere scritte in questo modo:

$bar = ${$scalarref}; 
push(@{$arrayref}, $filename); 
${$arrayref}[0] = "January"; 
${$hashref}{"KEY"} = "VALUE"; 
&{$coderef}(1,2,3); 
$globref->print("output\n"); # iff IO::Handle is loaded 

Certo, è un po 'sciocco utilizzare le graffe in questo caso, ma il blocco può contenere qualsiasi espressione arbitraria, in particolare, le espressioni pedice:

&{ $dispatch{$index} }(1,2,3); # call correct routine 

a causa di poter omettere le graffe per il semplice caso di $$x, le persone spesso fanno l'errore di visualizzazione dei simboli del dereferenziamento come operatori appropriati, e chiedo loro la precedenza. Se lo fossero, però, potresti usare parentesi invece di parentesi graffe. Questo non è il caso. Consideri la differenza sotto; caso 0 è una versione breve mano del caso 1, non è il caso 2:

$$hashref{"KEY"} = "VALUE";  # CASE 0 
${$hashref}{"KEY"} = "VALUE";  # CASE 1 
${$hashref{"KEY"}} = "VALUE";  # CASE 2 
${$hashref->{"KEY"}} = "VALUE"; # CASE 3 

Caso 2 è anche ingannevole in quanto state accedendo ad una variabile chiamata %hashref, non dereferenziazione attraverso $hashref per l'hash è presumibilmente riferimento. Sarebbe caso 3.

seguito in "I riferimenti simbolici":

abbiamo detto che i riferimenti primavera in esistenza, se necessario, se non sono definite, ma non abbiamo detto che cosa succede se un valore usato come riferimento è già definito, ma non è un riferimento difficile. Se lo usi come riferimento, verrà trattato come riferimento simbolico. Cioè, il valore dello scalare è considerato il nome di una variabile, piuttosto che un collegamento diretto ad un valore (possibilmente) anonimo.

+0

Grazie per la spiegazione esaustiva dei refs, ma la domanda riguardava il motivo per cui il contenuto di * {...} viene valutato in una stringa doppia citazione e se questo comportamento ha qualche utile applicazione. :) – willert

+1

@willert Sì, e ho citato dei passaggi specifici nella documentazione che spiegano cosa sta succedendo: annoti l'inizio della prima frase citata (enfasi aggiunta): "OVUNQUE tu avresti messo un identificatore ... puoi sostituire l'identificatore con un BLOCCO ... "Un blocco Perl è un codice arbitrario circondato da parentesi graffe. –

12

Spieghiamo questo in profondità in Intermediate Perl.

La sintassi generale per le ricerche variabili è:

SIGIL BLOCK INDEXY-THING 

Per un semplice scalare che assomiglia a:

print $ { foo }; 

probabilmente avete visto questo quando è necessario separare un nome di variabile dalle cose circostanti it:

print "abc${foo}def\n"; 

Se si dispone solo di un identificativo Perl nel blocco e nessun disordine circostante, è possibile lasciare fuori le parentesi graffe, che è il caso comune:

print $foo; 

Tuttavia, questa è la stessa cosa per dereferencing un riferimento:

SIGIL BLOCK-RETURNING-REFERENCE INDEXY-THINGS 

Se la cosa che si ottiene in il blocco è un riferimento, Perl cerca di dereferenziarlo come hai chiesto troppo:

my $ref = \ '12345'; 
print $  { $ref }; 

Questo è un vero e proprio blocco, però, e non solo lo zucchero. Si può avere il maggior numero di affermazioni che vuoi in là:

print $  { my $ref = \ '1234'; $ref }; 

Ora non sei solo specificando un identificatore di Perl, quindi Perl non si assume che si sta dando un identificatore ed esegue il codice e gli usi il risultato come riferimento. Si consideri la differenza tra questi quasi identiche say dichiarazioni:

use 5.010; 
our $foo = "I'm the scalar"; 

sub foo { \ "I'm the sub" } 

say ${foo}; 
say ${foo;}; 

In quel secondo say Perl vede il punto e virgola, si rende conto che non è un identificatore, interpreta il codice all'interno delle parentesi come testo, e restituisce il risultato. Poiché il risultato è un riferimento, utilizza lo ${...} per dereferenziarlo. Non importa dove lo fai, in modo che lo fai all'interno di una stringa doppia citazione non è speciale.

Inoltre, notare lo our lì. Questo è importante, ora che si sta andando a prendere in considerazione qualcosa di un po 'più complicato:

use 5.010; 
our $foo = "I'm the scalar"; 

sub foo { \ "I'm the sub" } 
sub baz { 'foo' } 

say ${foo}; 
say ${foo;}; 
say ${baz;}; 

Perl intreprets che lo scorso say come codice e vede il risultato non è un punto di riferimento; è la semplice stringa foo. Perl vede che non è un riferimento ma è ora in un contesto di dereferenziazione, quindi fa un riferimento simbolico (come Greg Bacon describes). Poiché i riferimenti simbolici funzionano con variabili nella tabella dei simboli, che $foo doveva essere una variabile di pacchetto.

Dal momento che è facile incasinare, strict ha un controllo pratico per questo. Tuttavia, quando lo spegni, non essere sorpreso quando ti morde. :)

Problemi correlati