Есть ли альтернатива Hash::Util для составных хешей?

У меня есть составной Hashref следующим образом

my $ch = {
    k1 => [ { k=>1 }, { m=>2 } ],
    k2 => [ { l=>90}, ... ],
};

Hash::Util::lock_hashref_recurse($ch) не эффективно блокирует эти значения..

@{$ch->{k1}}[0]->{k} = 'New value'; позволено! Как мне полностью заблокировать такой хэшреф?

5 ответов

Согласно документации:

Этот метод повторяется только в хешах, на которые ссылается другой хеш. Таким образом, хэш хэшей (HoH) будет ограничен, но хэш массивов хэшей (HoAoH) будет ограничен только верхним хешем.

И у вас есть хэш массивов хешей

use strictures;
use Hash::Util qw(lock_hash);
use Data::Visitor::Callback qw();

my $ch = {
    k1 => [{k => 1}, {m => 2}],
    k2 => [{l => 90},],
};

Data::Visitor::Callback->new(
    hash => sub {
        lock_hash %{ $_ }; 
        return $_;
    }
)->visit($ch);

$ch->{k1}[0]{k} = 'New value';
__END__
Modification of a read-only value attempted at …

Hash::Util сама предоставляет вам низкоуровневую функцию, которую вы можете реплицировать в Perl без функциональности XS: lock_hash / lock_hashref, Остальная функциональность, которая вам нужна, - это простой обход хеша, который может быть легко реализован вручную. Просматривать вложенные ссылки, сохраняя список посещенных и список найденных хэшей, а затем выполнить цикл по найденному списку с lock_hashref,

Как насчет Readonly?

Например

use Readonly;
Readonly my %h3 => (
    k1 => [ { k=>1 }, { m=>2 } ],
    k2 => [ { l=>90}, ],
);
print "old value: '$h3{k1}->[0]->{k}'\n";
$h3{k1}->[0]->{k} = 'New value';
print "new value: '$h3{k1}->[0]->{k}'\n";

дает

old value: '1'
Modification of a read-only value attempted at readonly.pl line 7

Обратите внимание, что %h3 это хэш, а не хэшреф. Хешрефы плохо работают с Readonly:

use Readonly;
Readonly my $h2 => {
    k1 => [ { k=>1 }, { m=>2 } ],
    k2 => [ { l=>90}, ],
};
print "old value: '$h2->{k1}->[0]->{k}'\n";
$h2->{k1}->[0]->{k} = 'New value';
print "new value: '$h2->{k1}->[0]->{k}'\n";

дает

old value: '1'
new value: 'New value'

Существует Const:: Fast, который может сделать любую переменную Perl полностью доступной только для чтения.

Однако вы не получите поведение Hash::Util "умри при чтении" при попытке прочитать нелегальный ключ.

Другие вопросы по тегам