2010-10-20 1 views
7

exists функция может unexpectedly autovivify entries в хешей.Почему `существует` изменяет мою константу?

Что меня удивляет, что такое поведение переносится на постоянных, а также:

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 

Выход

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

Я подозреваю, что это ошибка. Является ли это чем-то 5.10.1 конкретным, или другие версии Perl ведут себя одинаково?

+4

Вы можете отключить автовивитацию для любой лексической области, используя «no [autovivification] (http://search.cpan.org/perldoc?autovivification)». – rafl

+0

Мой вопрос был больше о изменчивом поведении констант с 'exist', а не о том, как я мог его избежать. – Zaid

+3

при работе с константами, помните, что 'use constant PI => 3.14' совпадает с' sub PI() {3.14} 'и' use constant data => {...} 'is' {my $ data = { ...}; sub data() {$ data}} ' –

ответ

15

Это документированное поведение. perldoc constant говорит:

Даже при том, что ссылка может быть объявлена ​​как константа, ссылка может указывать на данные, которые могут быть изменены , так как это показывает код.

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

Это ссылка, которая является постоянной, а не то, что он относится.

+0

Не могли бы вы объяснить, почему Perl выдает ошибку 'Can not modify const item in scalar assign' для' use constant var => 50; var = 40; ' – Zaid

+2

Потому что вы пытаетесь изменить константу. И вы не можете этого сделать. Константы ... ну ... постоянные. В этом весь смысл. Скалярное значение, которое вы сохраняете в константе, не может быть изменено. Но когда вы создаете константу из хеш-ссылки (как в вашем примере), это исправление, а не данные, на которые вы ссылаетесь. Ссылка - это скалярное значение, которое хранится в константе. –

+0

Хороший материал, я хотел бы +2 ответить на этот вопрос. – Zaid

9

Возможно, вы хотите использовать Readonly для создания констант «истина».

Константы, созданные с использованием constant прагма на самом деле inlinable subroutines. Это означает, что во время компиляции соответствующая скалярная константа вставляется непосредственно вместо некоторого вызова подпрограммы. Если константа является ссылкой, ничто не мешает вам изменять данные, на которые она указывает.

+0

Является константой hashref скалярной константы? – Zaid

+1

Не понимаю, как это ответ на вопрос? – ysth

+0

Используйте что-то вроде Data :: Lock (часть атрибута :: константа), а не Readonly. – MkV