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";
È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top