Проблема в том, что вы создаете копию хэша для работы в этой строке:
my %h2 = %{$hRef};
И это понятно, так как многие посты здесь на SO используют эту идиому для создания локального именидля хэша, без объяснения того, что он на самом деле делает копию.
В Perl хеш - это множественное число, как массив.Это означает, что в контексте списка (например, при присвоении хешу) агрегат разбирается на список его содержимого.Этот список пар затем собирается в новый хэш, как показано на рисунке.
Что вы хотите сделать, это работать со ссылкой напрямую.
for (keys %$hRef) {...}
for (values %$href) {...}
my $x = $href->{some_key};
# or
my $x = $$href{some_key};
$$href{new_key} = 'new_value';
При работе с обычным хешемсимвол, который является либо %
, когда речь идет о хэше, $
, когда речь идет об одном элементе, и @
, когда речь идет о срезе.За каждым из этих символов следует идентификатор.
%hash # whole hash
$hash{key} # element
@hash{qw(a b)} # slice
Для работы со ссылкой с именем $href
просто замените строку hash
в приведенном выше коде на $href
.Другими словами, $href
- это полное имя идентификатора:
%$href # whole hash
$$href{key} # element
@$href{qw(a b)} # slice
Каждый из них может быть записан в более подробной форме как:
%{$href}
${$href}{key}
@{$href}{qw(a b)}
Что опять-такиподстановка строки '$href'
вместо 'hash'
в качестве имени идентификатора.
%{hash}
${hash}{key}
@{hash}{qw(a b)}
Вы также можете использовать стрелку разыменования при работе с элементом:
$hash->{key} # exactly the same as $$hash{key}
НоЯ предпочитаю синтаксис удвоенных сигил, так как он похож на весь синтаксис совокупности и фрагментов, а также на обычный не эталонный синтаксис.
Итак, подведем итог, каждый раз, когда вы пишете что-то вроде этого:
my @array = @$array_ref;
my %hash = %$hash_ref;
Вы будете делать копию первого уровня каждого агрегата.При непосредственном использовании синтаксиса разыменования вы будете работать с фактическими значениями, а не с копией.
Если вы хотите РЕАЛЬНОЕ локальное имя для хэша, но хотите работать с тем же хэшем,Вы можете использовать ключевое слово local
для создания псевдонима.
sub some_sub {
my $hash_ref = shift;
our %hash; # declare a lexical name for the global %{__PACKAGE__::hash}
local *hash = \%$hash_ref;
# install the hash ref into the glob
# the `\%` bit ensures we have a hash ref
# use %hash here, all changes will be made to $hash_ref
} # local unwinds here, restoring the global to its previous value if any
Это чистый Perl способ наложения псевдонимов.Если вы хотите использовать переменную my
для хранения псевдонима, вы можете использовать модуль Data::Alias