Perché Perl valutare codice $ {...} durante l'interpolazione delle stringhe?
-
22-09-2019 - |
Domanda
Perché il seguente frammento di lavoro a tutti? E che male potrebbe essere possibile utilizzare questo? Ma sul serio, c'è qualche ragione, il codice in ${}
viene valutato a tutti e quindi utilizzato come riferimento ad uno scalare?
use strict;
no strict 'refs';
our $message = "Hello world!";
print "${ lc 'MESSAGE' }\n";
Soluzione
E 'ok, a meno di utilizzare riferimenti simbolici . 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";
Altri suggerimenti
Spieghiamo questo in profondità nel Intermediate Perl .
La sintassi generale per le ricerche variabili è:
SIGIL BLOCK INDEXY-THING
Per un semplice scalare che assomiglia a:
print $ { foo };
Hai probabilmente visto questo quando è necessario separare un nome di variabile dalle cose che lo circondano:
print "abc${foo}def\n";
Se v'è solo un identificatore 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 nel 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 che non sei solo specificando un identificatore di Perl, quindi Perl non si assume che si sta dando un identificatore ed esegue il codice e utilizza il risultato come un punto di riferimento. Si consideri la differenza tra queste affermazioni say
quasi identiche:
use 5.010;
our $foo = "I'm the scalar";
sub foo { \ "I'm the sub" }
say ${foo};
say ${foo;};
In questo 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 il ${...}
di dereferenziarlo. Non importa dove si esegue questa operazione, in modo che lo si fa all'interno di una stringa con virgolette doppie non è speciale.
Inoltre, notare la 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 foo
stringa. Perl vede che non è un punto di riferimento, ma è ora in un contesto dereferenziazione così si fa un riferimento simbolico (come Greg Bacone descrive ). Dal momento che i riferimenti simbolici lavorano con variabili nella tabella dei simboli, che $foo
doveva essere una variabile del pacchetto.
Dal momento che è facile rovinare questo in su, strict
ha un controllo a portata di mano per esso. Tuttavia, quando lo si spegne, non stupitevi quando ti morde. :)
"Uso Riferimenti" sezione della documentazione perlref :
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 subscripted:
&{ $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 si chiedono circa la loro la precedenza. Se lo fossero, però, è possibile utilizzare le parentesi tonde invece di parentesi graffe. Questo non è il caso. Prendere in considerazione la differenza di sotto; caso 0 è una versione stenografata del caso 1, non 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 si sta accedendo un
%hashref
variabile chiamata, non dereferenziazione attraverso$hashref
per l'hash è presumibilmente riferimento. Questo sarebbe il caso 3.
Più tardi nel "riferimenti simbolici":
Abbiamo detto che i riferimenti nascere all'improvviso, se necessario, se non sono definite, ma non abbiamo detto che cosa succede se un valore utilizzato come riferimento è già definita, ma non è un riferimento concreto. Se lo si utilizza come riferimento, sarà trattata come un riferimento simbolico. Cioè, il valore dello scalare è preso per essere il nome di una variabile, piuttosto che un collegamento diretto ad una (forse) il valore anonimo.