2010-10-20 15 views
7

La función exists puede unexpectedly autovivify entries en hashes.¿Por qué `exists` modifica mi constante?

Lo que me sorprende es que este comportamiento se traslada a las constantes así:

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 

salida

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

Sospecho que esto es un error. ¿Es esto algo específico de 5.10.1, o las otras versiones de Perl se comportan de manera similar?

+4

Puede desactivar la autovibución para cualquier alcance lóxico usando "no [autovivification] (http://search.cpan.org/perldoc?autovivification)". – rafl

+0

Mi pregunta era más sobre el comportamiento mutable de las constantes con 'exists' en lugar de cómo podría evitarlo. – Zaid

+3

cuando se trabaja con constantes, recuerde que 'use constante PI => 3.14' es lo mismo que' sub PI() {3.14} 'y' use constante data => {...} 'es' {my $ data = { ...}; sub data() {$ data}} ' –

Respuesta

15

Se ha documentado el comportamiento. perldoc constant dice:

A pesar de que una referencia puede ser declarada como una constante, la referencia puede apuntar a datos que pueden ser cambiado, ya que este código espectáculos.

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

Es la referencia que es constante, no en lo que se refiere a.

+0

¿Podría explicar por qué Perl arroja un error 'No se puede modificar el elemento constante en la asignación escalar' para' usar constante var => 50; var = 40; ' – Zaid

+2

Porque está intentando cambiar una constante. Y no puedes hacer eso. Las constantes son ... bueno ... constantes. Ese es el objetivo de ellos. El valor escalar que almacena en una constante no se puede cambiar. Pero cuando creas una constante a partir de una referencia hash (como en tu ejemplo), es la referencia la que se repara, no los datos a los que tienes referencia. La referencia es el valor escalar que se almacena en la constante. –

+0

Buenas cosas, ojalá pudiera +2 esta respuesta. – Zaid

9

Probablemente desee utilizar Readonly para crear constantes "verdaderas".

Las constantes creadas con el pragma constant son en realidad inlinable subroutines. Significa que en tiempo de compilación la constante escalar apropiada se inserta directamente en lugar de alguna llamada de subrutina. Si la constante es una referencia, nada le impide cambiar los datos a los que apunta.

+0

¿Es un hashref constante una constante escalar? – Zaid

+1

¿No veo cómo esta es una respuesta a la pregunta? – ysth

+0

Usa algo como Data :: Lock (parte de Attribute :: Constant) en lugar de Readonly. – MkV

Cuestiones relacionadas