2010-10-20 12 views
7

La fonction exists peut unexpectedly autovivify entries dans les hachages.Pourquoi `exists` modifie-t-il ma constante?

Ce qui me surprend est que ce comportement se répercute sur les constantes ainsi:

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 

Sortie

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

Je soupçonne que c'est un bug. Est-ce spécifique à 5.10.1, ou est-ce que les autres versions de Perl se comportent de la même façon?

+4

Vous pouvez désactiver l'autovivification pour toute portée lexicale en utilisant "no [autovivification] (http://search.cpan.org/perldoc?autovivification)". – rafl

+0

Ma question était plus sur le comportement mutable des constantes avec 'existes 'plutôt que sur comment je pourrais l'éviter. – Zaid

+3

lorsque vous utilisez des constantes, rappelez-vous que 'use constant PI => 3.14' est identique à' sub PI() {3.14} 'et' use constant data => {...} 'est' {my $ data = { ...}; sub data() {$ data}} ' –

Répondre

15

Ce comportement est documenté. perldoc constant dit:

Même si une référence peut être déclarée comme une constante, la référence peut pointer vers des données qui peuvent être changé, comme le montre de code.

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

Il est la référence qui est constante, pas ce qu'il se réfère.

+0

Pourriez-vous expliquer pourquoi Perl lance une erreur Impossible de modifier l'élément constant dans l'affectation scalaire pour 'use constant var => 50; var = 40; ' – Zaid

+2

Parce que vous essayez de changer une constante. Et tu ne peux pas faire ça. Les constantes sont ... bien ... constantes. C'est tout le point d'entre eux. La valeur scalaire que vous stockez dans une constante ne peut pas être modifiée. Mais lorsque vous créez une constante à partir d'une référence de hachage (comme dans votre exemple), c'est la référence qui est fixée, et non les données auxquelles vous faites référence. La référence est la valeur scalaire qui est stockée dans la constante. –

+0

Bonnes choses, j'aimerais pouvoir +2 cette réponse. – Zaid

9

Vous souhaitez probablement utiliser Readonly pour créer des constantes "true". Les constantes créées à l'aide du pragma constant sont en fait inlinable subroutines. Cela signifie qu'au moment de la compilation, la constante scalaire appropriée est insérée directement à la place d'un appel de sous-programme. Si la constante est une référence, rien ne vous empêche de modifier les données vers lesquelles elle pointe.

+0

Une constante hashref est-elle une constante scalaire? – Zaid

+1

Je ne vois pas comment c'est une réponse à la question? – ysth

+0

Utilisez quelque chose comme Data :: Lock (partie d'Attribute :: Constant) plutôt que Readonly. – MkV