2010-10-20 5 views
7

Die exists Funktion kann unexpectedly autovivify entries in Hashes.Warum ist `Existieren` meine Konstante zu modifizieren?

Was mich wundert ist, dass dieses Verhalten auch auf Konstanten überträgt sich:

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 

Ausgabe

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

Ich vermute, dies ein Fehler ist. Ist das etwas 5.10.1-spezifisch oder verhalten sich andere Versionen von Perl ähnlich?

+4

Sie können die Autovivifizierung für jeden lexikalischen Bereich mit "no [autovivification] (http://search.cpan.org/perldoc?autovivification)" deaktivieren. – rafl

+0

Meine Frage war mehr über das veränderliche Verhalten von Konstanten mit 'exists' und nicht, wie ich es vermeiden könnte. – Zaid

+3

Wenn Sie mit Konstanten arbeiten, denken Sie daran, dass 'Konstante PI verwenden => 3.14 'dasselbe ist wie' Sub PI() {3.14}' und 'Konstante Daten verwenden => {...}' ist '{my $ data = { ...}; Subdaten() {$ Daten}} ' –

Antwort

15

Dies ist dokumentiertes Verhalten. perldoc constant sagt:

Auch wenn eine Referenz als Konstante deklarierte sein kann, die Referenz auf Daten verweisen kann, die geändert, wie dieser Code zeigt werden kann.

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

Es ist die Referenz, die konstant ist, nicht das, was sie sich bezieht.

+0

Könnten Sie erklären, warum Perl für 'constant var => 50; var = 40; ' – Zaid

+2

Weil Sie versuchen, eine Konstante zu ändern. Und das kannst du nicht tun. Konstanten sind ... nun ... konstant. Das ist der springende Punkt von ihnen. Der skalare Wert, den Sie in einer Konstante speichern, kann nicht geändert werden. Aber wenn Sie eine Konstante aus einer Hash-Referenz erstellen (wie in Ihrem Beispiel), ist es die Referenz, die festgelegt ist, nicht die Daten, auf die Sie verweisen. Die Referenz ist der Skalarwert, der in der Konstanten gespeichert ist. –

+0

Gute Sachen, ich wünschte, ich könnte +2 diese Antwort. – Zaid

9

Sie möchten wahrscheinlich Readonly zum Erstellen "True" -Konstanten verwenden.

Konstanten erstellt mit dem constant Pragma sind eigentlich inlinable subroutines. Dies bedeutet, dass zur Kompilierungszeit die entsprechende skalare Konstante direkt anstelle eines Unterprogrammaufrufs eingefügt wird. Wenn die Konstante eine Referenz ist, verhindert nichts, dass Sie die Daten ändern, auf die sie zeigt.

+0

Ist ein konstanter Hashref eine skalare Konstante? – Zaid

+1

Ich sehe nicht, wie das eine Antwort auf die Frage ist? – ysth

+0

Verwenden Sie etwas wie Data :: Lock (Teil von Attribute :: Constant) anstatt Readonly. – MkV

Verwandte Themen