2010-10-20 13 views
7

La funzione exists può essere unexpectedly autovivify entries in hash.Perché `exists` modifica la mia costante?

Quello che mi sorprende è che questo comportamento trasporta oltre alle costanti così:

use strict; 
use warnings; 
use Data::Dump 'dump'; 

use constant data => { 
         'foo' => { 
            'bar' => 'baz', 
           }, 
         'a' => { 
            'b' => 'c', 
           } 
        }; 

dump data; # Pre-modified 

print "No data for 'soda->cola->pop'\n" unless exists data->{soda}{cola}{pop}; 

dump data; # data->{soda}{cola} now sprung to life 

uscita

{ a => { b => "c" }, foo => { bar => "baz" } } 
No data for 'soda->cola->pop' 
{ a => { b => "c" }, foo => { bar => "baz" }, soda => { cola => {} } } 

Ho il sospetto che questo è un bug. Si tratta di qualcosa di specifico 5.10.1, o le altre versioni di Perl si comportano in modo simile?

+4

È possibile disattivare l'autovivificazione per qualsiasi ambito lessicale utilizzando "no [autovivification] (http://search.cpan.org/perldoc?autovivification)". – rafl

+0

La mia domanda riguardava più il comportamento mutabile delle costanti con 'exists' piuttosto che il modo in cui potevo evitarlo. – Zaid

+3

quando si lavora con le costanti, ricorda che 'usa costante PI => 3.14' è uguale a' sub PI() {3.14} 'e' usa costante dati => {...} 'è' {my $ data = { ...}; sub data() {$ data}} ' –

risposta

15

Questo comportamento è documentato. perldoc constant dice:

Anche se un riferimento può essere dichiarata come costante, il riferimento può puntare a dati che possono essere cambiati , come dimostra questo codice.

use constant ARRAY => [ 1,2,3,4 ]; 
print ARRAY->[1]; 
ARRAY->[1] = " be changed"; 
print ARRAY->[1]; 

È il riferimento che è costante, non cosa si riferisce.

+0

Puoi spiegare perché Perl genera un errore 'Impossibile modificare l'elemento costante nell'assegnazione scalare' per' use constant var => 50; var = 40; ' – Zaid

+2

Perché stai provando a cambiare una costante. E tu non puoi farlo. Le costanti sono ... beh ... costanti. Questo è il punto centrale di loro. Il valore scalare che si memorizza in una costante non può essere modificato. Ma quando crei una costante da un riferimento hash (come nel tuo esempio) è il riferimento che viene corretto, non i dati a cui hai un riferimento. Il riferimento è il valore scalare che è memorizzato nella costante. –

+0

Roba buona, vorrei poter +2 questa risposta. – Zaid

9

Probabilmente si desidera utilizzare Readonly per la creazione di costanti "vere".

Le costanti create utilizzando il pragma constant sono in realtà inlinable subroutines. Significa che al momento della compilazione la costante scalare appropriata viene inserita direttamente al posto di alcune chiamate di subroutine. Se la costante è un riferimento, nulla ti impedisce di modificare i dati a cui punta.

+0

È un hashref costante una costante scalare? – Zaid

+1

Non vedo come questa sia una risposta alla domanda? – ysth

+0

Utilizzare qualcosa come Data :: Lock (parte di Attribute :: Constant) piuttosto che Readonly. – MkV