Ключевые слова:perl, hash, (найти похожие документы)
Date: Wed, 17 Apr 2002 11:39:00 +0400
From: Bulat Ziganshin <[email protected]>
Newsgroups: fido7.ru.perl
Subject: Хэш хэшей в Perl - вложенные массивы и хеши
VP>> my %hash2 = qw(d 3 e 4);
VP>> $hash1{'c'} = \%hash2;
AM> А %hash2 можно динамически создавать по мере появления новых ключей у
AM> %hash1?
не всегда :) есть perldsc, вот его кратокое изложение
=== Cut ===
ну очень краткое :) итак, как работать в perl с вложенными массивами и хешами
до perl5 в перле было всего три (основных) типа данных и имя переменной
полностью определяло, данные какого типа она хранит
$x - хранит ЗHАЧЕHИЕ (число или строку)
@x - хранит список ЗHАЧЕHИЙ
%x - хранит список пар строка->ЗHАЧЕHИЕ
в perl5 всё осталось также, только понятие ЗHАЧЕHИЯ было расширено - теперь это
может быть ССЫЛКА на массив или хеш. очень важная тонкость - в отличие от
самого массива или хеша, ССЫЛКА на них является скаляром. вот смотрите:
@a = (1,2);
$a = [ (1,2) ]; # квадратные скобки превращают массив/хеш в ССЫЛКУ на массив
%b = (1=>2);
$b = { (1=>2) }; # фигурные скобки превращают массив/хеш в ССЫЛКУ на хеш
обратите внимания - круглые скобки используются только для группировки, а
квадратные и фигурные являются ОПЕРАТОРОМ, превращающим СОСТАВHОЕ ЗHАЧЕHИЕ в
ССЫЛКУ. Внутри []/{} круглые скобки обычно опускают, я привёл их лишь для
удобства понимания единственной существенной разницы между этими действиями
теперь несложно сконструировать массив массивов:
@c = ( [1,2], [2], [3,4,5] );
на самом деле, конечно, это массив ССЫЛОК на массивы. но к его элементам можно
обращаться, не задумываясь об этом - $c[0][1]
или создадим хеш хешей:
%d = ( C=> {Speed=>Good, Readability=>Bad}, Perl=>{Speed=>hmmm} );
опять же, $d{Perl}{Speed} будет работать
если же вы и внешние круглые скобки замените на []/{}, то опять получите
скаляр, и его надо будет присваивать тоже скаляру:
$e = [ [1,2], [3,4] ]; # ССЫЛКА на массив, состоящий из ССЫЛОК на массивы
поскольку перловые функции обычно ожидают "развёрнутый" массив/хеш,
пользоваться таким скаляром будет неудобно. да и к элементам его доступ
неочевиден - $e->[0][1]. собственно, "->" - оператор разыменования ССЫЛОК, и
для доступа к элементам @c он тоже используется, но перл вставляет его неявно:
$c[0][1] эквивалентно $c[0]->[1]. То есть, $c[0] возвращает нам ССЫЛКУ на
массив, стрелка её разыменовывает (превращает ССЫЛКУ в массив) и затем второе
индексирование "[1]" возвращает нам элемент этого массива
наверно, уже понятно, что $e->[0][1] на самом деле работает как $e->[0]->[1]:
разыменовываем, берём элемент, снова разыменовываем, и снова берём элемент. с
массивами хешей, и со сколь угодно более сложными структурами данных всё точно
также. разумеется, их можно произвольно смешивать:
$a = [ 1, [2,3], {a=>b}, [[4,5]] ];
1 == $a->[0]
2 == $a->[1][0]
b == $a->[2]->{a} == $a->[2]{a}
5 == $a->[3][0][1]
вот, в общем-то, и всё. добавлю несколько дополнительных замечаний
операторы []/{} создают КОПИИ переданных им ЗHАЧЕHИЙ. если вы хотите вместо
этого получить ССЫЛКУ на ТЕ ЖЕ данные, используйте оператор "\". кстати, эти
операторы можно комбинировать:
@a = (1,2);
@b = (3,4);
@c = ( [@a], [@b] ); # @c содержит (ССЫЛКИ на) копии массивов a и b
@d = ( \@a, \@b ); # @d содержит ССЫЛКИ на массивы a и b
@e = ( [\@a, \@b], [[@a], [@b]] );
@e - трёхмерный массив,
$e[0][0][$i] эквивалентно $a[$i]
$e[0][1][$i] эквивалентно $b[$i]
$e[1][0][$i] содержат копии $a[$i]
$e[1][1][$i] содержат копии $b[$i]
т.е. теперь присваивания $a[$i] изменят также ЗHАЧЕHИЯ $d[0][$i] и $e[0][0][$i]
и наоборот. ссылки полезны при передаче сложных структур данных в функции (чтоб
перл не разворачивал всё в один бессмысленный список) и при манипуляциях со
связными структурами данных, типа деревьев и связных списков
не используйте операцию получения ссылки без необходимости, поскольку перл
возвращает ССЫЛКУ не на данные как таковые, а на переменную, и в дальнейшем что
бы ни присвоили этой переменной - вы увидите это по своей ссылке:
@a = (1,2);
$ref = \@a;
@a = (3,4);
# теперь $ref указывает на новое содержимое @a
второе замечание - многие встроенные операторы перла рассчитаны на то, что им
на вход подадут переменную-массив или хеш. но никак не ССЫЛКУ. для того, чтобы
превратить одно в другое, используются конструкции @{...} и %{...}:
push @{$c[0]}, 0; # $c[0] - ССЫЛКА на массив, @{$c[0]} - сам массив
%d = ( C=> {Speed=>Good, Readability=>Bad}, Perl=>{Speed=>hmmm} );
print keys %{$d{C}} # $d{C} - ССЫЛКА на хеш, %{$d{C}} - сам хеш
остатнее читайте в perldsc. там же есть готовые куски кода для всех возможных
манипуляций с массивами массивов, массивами хешей, хешами массивов и хешами
хешей. от себя посоветую использовать модуль Data::Dumper для изучения
результатов своего творчества :)
use Data::Dumper; # for exporting values from Perl to Ruby
#$Data::Dumper::Indent = 0; # one-line output
#$Data::Dumper::Terse = 1; # print no assignments to $VARn
#$Data::Dumper::Useqq = 1; # quote unprintable chars
#$Data::Dumper::Deepcopy = 1; # ??? are we really need this? ;)
print Dumper(\$a), "\n", Dumper(\@e), "\n", Dumper(\%d);
=== Cut ===
Bulat, mailto:bulatz-AT-fort.tatarstan.ru, ICQ: work 15872722, home 11849833
... Иногда для того, чтобы изменить свое восприятие мира,
... люди пытаются изменить сам мир