perldsc
СОДЕРЖАНИЕ
- ИМЯ
- ОПИСАНИЕ
- ССЫЛКИ
- ОБЩИЕ ОШИБКИ
- ЗАМЕЧАНИЕ ПО ПРИОРИТЕТУ
- ПОЧЕМУ ВЫ ДОЛЖНЫ ВСЕГДА ИСПОЛЬЗОВАТЬ VERSION
- ОТЛАДКА
- ПРИМЕРЫ КОДА
- МАССИВЫ МАССИВОВ
- ХЭШИ МАССИВОВ
- МАССИВЫ ХЭШЕЙ
- ХЭШИ ХЭШЕЙ
- БОЛЕЕ СЛОЖНЫЕ СТРУКТУРЫ
- Связи с базой данных
- СМОТРИТЕ ТАКЖЕ
- АВТОР
ИМЯ
perldsc - Справочник по структурам данных Perl
ОПИСАНИЕ
Perl позволяет использовать сложные структуры данных. Вы можете написать что-то вроде этого, и вдруг у вас будет массив с тремя измерениями!
for my $x (1 .. 10) {
for my $y (1 .. 10) {
for my $z (1 .. 10) {
$AoA[$x][$y][$z] =
$x ** $y + $z;
}
}
} Однако, как бы просто это ни выглядело, на самом деле это гораздо более сложная конструкция, чем кажется на первый взгляд!
Как его вывести на печать? Почему нельзя просто написать print @AoA? Как его отсортировать? Как передать его в функцию или получить из функции? Это объект? Можно ли сохранить его в файле для последующего чтения? Как получить целые строки или столбцы этой матрицы? Все значения должны быть числовыми?
Как видите, легко запутаться. Хотя часть вины лежит на реализации ссылок, это в большей степени связано с отсутствием существующей документации с примерами, предназначенными для начинающих.
Этот документ призван быть подробным, но понятным руководством по различным типам структур данных, которые вы можете захотеть разработать. Он также должен служить кулинарной книгой с примерами. Таким образом, когда вам нужно создать одну из этих сложных структур данных, вы можете просто скопировать, скопировать или позаимствовать готовый пример отсюда.
Давайте рассмотрим каждую из этих возможных конструкций подробно. Есть отдельные разделы для каждого из следующих пунктов:
-
массивы массивов
-
хэши массивов
-
массивы хэшей
-
хэши хэшей
-
более сложные конструкции
Но пока давайте рассмотрим общие проблемы, характерные для всех этих типов структур данных.
ССЫЛКИ
Самое важное, что нужно понимать о всех структурах данных в Perl — включая многомерные массивы — это то, что, хотя они могут выглядеть иначе, Perl @ARRAY и %HASH в итоге являются одномерными. Они могут содержать только скалярные значения (то есть строку, число или ссылку). Они не могут напрямую содержать другие массивы или хэши, а вместо этого содержат ссылки на другие массивы или хэши.
Вы не можете использовать ссылку на массив или хэш так же, как реальный массив или хэш. Для программистов C или C++, не привыкших различать массивы и указатели на них, это может быть запутанно. Если это так, просто подумайте о разнице между структурой и указателем на структуру.
Вы можете (и должны) узнать больше о ссылках в perlref. Вкратце, ссылки похожи на указатели, которые знают, на что они указывают. (Объекты также являются типом ссылки, но нам они пока не понадобятся — если вообще когда-либо.) Это означает, что когда у вас есть что-то, что кажется вам доступом к двух- или более мерному массиву и/или хэшу, на самом деле происходит следующее: базовый тип представляет собой всего лишь одномерный элемент, содержащий ссылки на следующий уровень. Просто вы можете использовать его так, как будто это двухмерный массив. Это, в принципе, то, как работают почти все многомерные массивы в C.
$array[7][12] # array of arrays
$array[7]{string} # array of hashes
$hash{string}[7] # hash of arrays
$hash{string}{'another string'} # hash of hashes Теперь, поскольку верхний уровень содержит только ссылки, если вы попытаетесь вывести свой массив с помощью простой функции print(), вы получите что-то не очень приятное, например:
my @AoA = ( [2, 3], [4, 5, 7], [0] );
print $AoA[1][2];
7
print @AoA;
ARRAY(0x83c38)ARRAY(0x8b194)ARRAY(0x8b1d0) Это связано с тем, что Perl не (никогда) неявно разыменовывает ваши переменные. Если вы хотите получить то, на что ссылается ссылка, вам нужно сделать это самостоятельно, используя префиксные индикаторы типа, такие как ${$blah}, @{$blah}, @{$blah[$i]}, или же постфиксные стрелки указателей, такие как $a->[3], $h->{fred}, или даже $ob->method()->[3].
ОБЩИЕ ОШИБКИ
Две наиболее распространенные ошибки при создании чего-то вроде массива массивов — это либо случайное подсчет элементов, либо повторное присвоение ссылки на один и тот же адрес памяти. Вот случай, когда вы получаете только количество, а не вложенный массив:
for my $i (1..10) {
my @array = somefunc($i);
$AoA[$i] = @array; # WRONG!
} Это просто случай, когда массив присваивается скаляру, и получается его размер. Если это то, что вы действительно хотите, то вам стоит быть более явными, например так:
for my $i (1..10) {
my @array = somefunc($i);
$counts[$i] = scalar @array;
} Вот случай повторного присвоения ссылки на один и тот же адрес памяти:
# Either without strict or having an outer-scope my @array;
# declaration.
for my $i (1..10) {
@array = somefunc($i);
$AoA[$i] = \@array; # WRONG!
} Так в чем проблема? Это выглядит правильно, не так ли? Ведь я только что сказал вам, что вам нужен массив ссылок, так что вы сделали мне его!
К сожалению, хотя это и так, но это все равно некорректно. Все ссылки в @AoA указывают на один и тот же адрес, и поэтому они все будут содержать то, что было последним в @array! Это аналогично проблеме, продемонстрированной в следующей программе C:
#include <pwd.h>
main() {
struct passwd *getpwnam(), *rp, *dp;
rp = getpwnam("root");
dp = getpwnam("daemon");
printf("daemon name is %s\nroot name is %s\n",
dp->pw_name, rp->pw_name);
} Что выведет
daemon name is daemon
root name is daemon Проблема в том, что как rp, так и dp являются указателями на одну и ту же область памяти! В C вам нужно помнить, что нужно использовать malloc(). В Perl вы захотите использовать конструктор массива [] или конструктор хэша {} вместо этого. Вот правильный способ выполнить предыдущие фрагменты кода:
# Either without strict or having an outer-scope my @array;
# declaration.
for my $i (1..10) {
@array = somefunc($i);
$AoA[$i] = [ @array ];
} Квадратные скобки создают ссылку на новый массив с копией того, что содержится в @array на момент присваивания. Именно это вы и хотите.
Обратите внимание, что это приведет к чему-то подобному:
# Either without strict or having an outer-scope my @array;
# declaration.
for my $i (1..10) {
@array = 0 .. $i;
$AoA[$i]->@* = @array;
} Это то же самое? Возможно, да — возможно, и нет. Суть в том, что при присваивании с использованием квадратных скобок вы точно знаете, что это всегда новая ссылка с новой копией данных. Что-то еще может происходить в этом новом случае с разыменовыванием $AoA[$i]->@* слева от оператора присваивания. Все зависит от того, был ли $AoA[$i] не определен изначально или уже содержал ссылку. Если вы уже заполнили @AoA ссылками, как в
$AoA[3] = \@another_array; Тогда присваивание со ссылками слева от оператора присваивания будет использовать уже существующую ссылку:
$AoA[3]->@* = @array; Конечно, это повлечёт за собой «интересный» эффект — уничтожение @another_array. (Вы замечали, как, когда программист говорит, что что-то «интересно», вместо того, чтобы подразумевать «занимательно», они, скорее, предполагают «раздражающее», «сложное» или оба?)
Поэтому всегда помните, что нужно использовать конструкторы массивов или хэшей с [] или {}, и все будет в порядке, хотя это не всегда оптимально эффективно.
Удивительно, но следующее, на вид опасное, выражение фактически сработает:
for my $i (1..10) {
my @array = somefunc($i);
$AoA[$i] = \@array;
} Это потому, что my() больше похож на оператор выполнения во время исполнения, чем на объявление во время компиляции. Это означает, что переменная my() создается заново каждый раз по циклу. Поэтому, даже если это выглядит так, как будто вы храните одну и ту же ссылку на переменную каждый раз, вы этого не делаете! Это тонкое различие может сделать код более эффективным, но в то же время ввести в заблуждение всех, кроме самых опытных программистов. Поэтому я обычно не советую рассказывать об этом новичкам. На самом деле, кроме передачи аргументов в функции, я редко использую оператор получения ссылки (обратная косая черта) в коде. Вместо этого я советую начинающим (и большинству из нас), что нужно пытаться использовать более понятные конструкторы [] и {} вместо полагания на лексическое (или динамическое) область видимости и скрытое подсчет ссылок, чтобы все делалось правильно за кулисами.
Обратите также внимание, что существует еще один способ написания разыменовывания! Эти две строки эквивалентны:
$AoA[$i]->@* = @array;
@{ $AoA[$i] } = @array; Первый вариант, называемый постфиксным разыменовыванием, обычно легче читать, потому что выражение можно читать слева направо, и нет необходимости согласовывать скобки. С другой стороны, он также новее. Он был добавлен в язык в 2014 году, поэтому в старом коде вы часто встретите другой вариант — окружающее разыменование.
Подводя итог:
$AoA[$i] = [ @array ]; # usually best
$AoA[$i] = \@array; # perilous; just how my() was that array?
$AoA[$i]->@* = @array; # way too tricky for most programmers
@{ $AoA[$i] } = @array; # just as tricky, and also harder to read ЗАМЕЧАНИЕ ПО ПРИОРИТЕТУ
Говоря о таких вещах, как @{$AoA[$i]}, следующее на самом деле то же самое:
$aref->[2][2] # clear
$$aref[2][2] # confusing Это потому, что правила приоритета Perl для пяти префиксных дериференсеров (которые выглядят как будто кто-то ругается: $ @ * % &) делают их связью более жёсткой, чем постфиксные индексы в квадратных или фигурных скобках! Это, несомненно, станет большим шоком для программиста C или C++, который привык использовать *a[i] для обозначения того, что указано i'м элементом a. То есть они сначала берут индекс, а затем только дериференсируют значение по этому индексу. В C это нормально, но это не C.
По-видимому, эквивалентная конструкция в Perl, $$aref[$i] сначала выполняет дериференсирование $aref, что делает его ссылкой на массив, затем дериференсирует его и, наконец, сообщает вам i'м значение массива, на который указывает $AoA. Если вам нужна концепция C, вы можете написать $AoA[$i]->$* для явного дериференсирования i'м элемента, читая слева направо.
ПОЧЕМУ ВЫ ДОЛЖНЫ ВСЕГДА use VERSION
Если это начинает звучать пугающе, успокойтесь. Perl имеет некоторые функции, которые помогут вам избежать наиболее распространённых ошибок. Один из способов избежать путаницы — начать каждую программу с:
use strict; Таким образом, вы будете вынуждены объявлять все свои переменные с помощью my() и также запретите случайное "символическое дериференсирование". Поэтому если бы вы сделали так:
my $aref = [
[ "fred", "barney", "pebbles", "bambam", "dino", ],
[ "homer", "bart", "marge", "maggie", ],
[ "george", "jane", "elroy", "judy", ],
];
print $aref[2][2]; Компилятор сразу же отметит это как ошибку во время компиляции, потому что вы случайно обращались к @aref, не объявленной переменной, и тем самым напомнит вам написать вместо этого:
print $aref->[2][2] С версии Perl 5.12, объявление use VERSION также активирует прагму strict. Кроме того, это также активирует набор функций, предоставляя более полезные возможности. С версии 5.36 это также включит прагму warnings. Часто лучший способ активировать все эти вещи сразу — начать файл с:
use v5.36; Таким образом, каждый файл будет начинаться с strict, warnings, и многих полезных именованных функций, а также нескольких более старых функций будут выключены (таких как indirect). Дополнительную информацию см. в "use VERSION" в perlfunc.
ОТЛАДКА
Вы можете использовать команду отладчика x для вывода сложных структур данных. Например, при присваивании $AoA выше, вот вывод отладчика:
DB<1> x $AoA
$AoA = ARRAY(0x13b5a0)
0 ARRAY(0x1f0a24)
0 'fred'
1 'barney'
2 'pebbles'
3 'bambam'
4 'dino'
1 ARRAY(0x13b558)
0 'homer'
1 'bart'
2 'marge'
3 'maggie'
2 ARRAY(0x13b540)
0 'george'
1 'jane'
2 'elroy'
3 'judy' ПРИМЕРЫ КОДА
Представленные здесь короткие примеры кода иллюстрируют доступ к различным типам структур данных с минимальными комментариями.
МАССИВЫ МАССИВОВ
Объявление МАССИВА МАССИВОВ
my @AoA = (
[ "fred", "barney" ],
[ "george", "jane", "elroy" ],
[ "homer", "marge", "bart" ],
); Генерация МАССИВА МАССИВОВ
# reading from file
while ( <> ) {
push @AoA, [ split ];
}
# calling a function
for my $i ( 1 .. 10 ) {
$AoA[$i] = [ somefunc($i) ];
}
# using temp vars
for my $i ( 1 .. 10 ) {
my @tmp = somefunc($i);
$AoA[$i] = [ @tmp ];
}
# add to an existing row
push $AoA[0]->@*, "wilma", "betty"; Доступ и вывод МАССИВА МАССИВОВ
# one element
$AoA[0][0] = "Fred";
# another element
$AoA[1][1] =~ s/(\w)/\u$1/;
# print the whole thing with refs
for my $aref ( @AoA ) {
print "\t [ @$aref ],\n";
}
# print the whole thing with indices
for my $i ( 0 .. $#AoA ) {
print "\t [ $AoA[$i]->@* ],\n";
}
# print the whole thing one at a time
for my $i ( 0 .. $#AoA ) {
for my $j ( 0 .. $AoA[$i]->$#* ) {
print "elem at ($i, $j) is $AoA[$i][$j]\n";
}
} МАССИВЫ ХЭШОВ
Объявление МАССИВА ХЭШОВ
my %HoA = (
flintstones => [ "fred", "barney" ],
jetsons => [ "george", "jane", "elroy" ],
simpsons => [ "homer", "marge", "bart" ],
); Генерация МАССИВА ХЭШОВ
# reading from file
# flintstones: fred barney wilma dino
while ( <> ) {
next unless s/^(.*?):\s*//;
$HoA{$1} = [ split ];
}
# reading from file; more temps
# flintstones: fred barney wilma dino
while ( my $line = <> ) {
my ($who, $rest) = split /:\s*/, $line, 2;
my @fields = split ' ', $rest;
$HoA{$who} = [ @fields ];
}
# calling a function that returns a list
for my $group ( "simpsons", "jetsons", "flintstones" ) {
$HoA{$group} = [ get_family($group) ];
}
# likewise, but using temps
for my $group ( "simpsons", "jetsons", "flintstones" ) {
my @members = get_family($group);
$HoA{$group} = [ @members ];
}
# append new members to an existing family
push $HoA{flintstones}->@*, "wilma", "betty"; Доступ и вывод МАССИВА ХЭШОВ
# one element
$HoA{flintstones}[0] = "Fred";
# another element
$HoA{simpsons}[1] =~ s/(\w)/\u$1/;
# print the whole thing
foreach my $family ( keys %HoA ) {
print "$family: $HoA{$family}->@* \n"
}
# print the whole thing with indices
foreach my $family ( keys %HoA ) {
print "family: ";
foreach my $i ( 0 .. $HoA{$family}->$#* ) {
print " $i = $HoA{$family}[$i]";
}
print "\n";
}
# print the whole thing sorted by number of members
foreach my $family ( sort { $HoA{$b}->@* <=> $HoA{$a}->@* } keys %HoA ) {
print "$family: $HoA{$family}->@* \n"
}
# print the whole thing sorted by number of members and name
foreach my $family ( sort {
$HoA{$b}->@* <=> $HoA{$a}->@*
||
$a cmp $b
} keys %HoA )
{
print "$family: ", join(", ", sort $HoA{$family}->@* ), "\n";
} МАССИВЫ ХЭШОВ
Объявление МАССИВА ХЭШОВ
my @AoH = (
{
Lead => "fred",
Friend => "barney",
},
{
Lead => "george",
Wife => "jane",
Son => "elroy",
},
{
Lead => "homer",
Wife => "marge",
Son => "bart",
}
); Генерация МАССИВА ХЭШОВ
# reading from file
# format: LEAD=fred FRIEND=barney
while ( <> ) {
my $rec = {};
for my $field ( split ) {
my ($key, $value) = split /=/, $field;
$rec->{$key} = $value;
}
push @AoH, $rec;
}
# reading from file
# format: LEAD=fred FRIEND=barney
# no temp
while ( <> ) {
push @AoH, { split /[\s+=]/ };
}
# calling a function that returns a key/value pair list, like
# "lead","fred","daughter","pebbles"
while ( my %fields = getnextpairset() ) {
push @AoH, { %fields };
}
# likewise, but using no temp vars
while (<>) {
push @AoH, { parsepairs($_) };
}
# add key/value to an element
$AoH[0]{pet} = "dino";
$AoH[2]{pet} = "santa's little helper"; Доступ и вывод МАССИВА ХЭШОВ
# one element
$AoH[0]{lead} = "fred";
# another element
$AoH[1]{lead} =~ s/(\w)/\u$1/;
# print the whole thing with refs
for my $href ( @AoH ) {
print "{ ";
for my $role ( keys %$href ) {
print "$role=$href->{$role} ";
}
print "}\n";
}
# print the whole thing with indices
for my $i ( 0 .. $#AoH ) {
print "$i is { ";
for my $role ( keys $AoH[$i]->%* ) {
print "$role=$AoH[$i]{$role} ";
}
print "}\n";
}
# print the whole thing one at a time
for my $i ( 0 .. $#AoH ) {
for my $role ( keys $AoH[$i]->%* ) {
print "elem at ($i, $role) is $AoH[$i]{$role}\n";
}
} ХЭШИ ХЭШОВ
Объявление ХЭША ХЭШОВ
my %HoH = (
flintstones => {
lead => "fred",
pal => "barney",
},
jetsons => {
lead => "george",
wife => "jane",
"his boy" => "elroy",
},
simpsons => {
lead => "homer",
wife => "marge",
kid => "bart",
},
); Генерация ХЭША ХЭШОВ
# reading from file
# flintstones: lead=fred pal=barney wife=wilma pet=dino
while ( <> ) {
next unless s/^(.*?):\s*//;
my $who = $1;
for my $field ( split ) {
my ($key, $value) = split /=/, $field;
$HoH{$who}{$key} = $value;
}
}
# reading from file; more temps
while ( <> ) {
next unless s/^(.*?):\s*//;
my $who = $1;
my $rec = {};
$HoH{$who} = $rec;
for my $field ( split ) {
my ($key, $value) = split /=/, $field;
$rec->{$key} = $value;
}
}
# calling a function that returns a key,value hash
for my $group ( "simpsons", "jetsons", "flintstones" ) {
$HoH{$group} = { get_family($group) };
}
# likewise, but using temps
for my $group ( "simpsons", "jetsons", "flintstones" ) {
my %members = get_family($group);
$HoH{$group} = { %members };
}
# append new members to an existing family
my %new_folks = (
wife => "wilma",
pet => "dino",
);
for my $what (keys %new_folks) {
$HoH{flintstones}{$what} = $new_folks{$what};
} Доступ и вывод ХЭША ХЭШОВ
# one element
$HoH{flintstones}{wife} = "wilma";
# another element
$HoH{simpsons}{lead} =~ s/(\w)/\u$1/;
# print the whole thing
foreach my $family ( keys %HoH ) {
print "$family: { ";
for my $role ( keys $HoH{$family}->%* ) {
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}
# print the whole thing somewhat sorted
foreach my $family ( sort keys %HoH ) {
print "$family: { ";
for my $role ( sort keys $HoH{$family}->%* ) {
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}
# print the whole thing sorted by number of members
foreach my $family ( sort { $HoH{$b}->%* <=> $HoH{$a}->%* } keys %HoH ) {
print "$family: { ";
for my $role ( sort keys $HoH{$family}->%* ) {
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
}
# establish a sort order (rank) for each role
my $i = 0;
my %rank;
for ( qw(lead wife son daughter pal pet) ) { $rank{$_} = ++$i }
# now print the whole thing sorted by number of members
foreach my $family ( sort { $HoH{$b}->%* <=> $HoH{$a}->%* } keys %HoH ) {
print "$family: { ";
# and print these according to rank order
for my $role ( sort { $rank{$a} <=> $rank{$b} }
keys $HoH{$family}->%* )
{
print "$role=$HoH{$family}{$role} ";
}
print "}\n";
} БОЛЕЕ СЛОЖНЫЕ ЗАПИСИ
Объявление БОЛЕЕ СЛОЖНЫХ ЗАПИСЕЙ
Вот пример, показывающий, как создать и использовать запись, поля которой имеют различные типы:
my $rec = {
TEXT => $string,
SEQUENCE => [ @old_values ],
LOOKUP => { %some_table },
THATCODE => \&some_function,
THISCODE => sub { $_[0] ** $_[1] },
HANDLE => \*STDOUT,
};
print $rec->{TEXT};
print $rec->{SEQUENCE}[0];
my $last = pop $rec->{SEQUENCE}->@*;
print $rec->{LOOKUP}{"key"};
my ($first_k, $first_v) = each $rec->{LOOKUP}->%*;
my $answer = $rec->{THATCODE}->($arg);
$answer = $rec->{THISCODE}->($arg1, $arg2);
# careful of extra block braces on fh ref
print { $rec->{HANDLE} } "a string\n";
use FileHandle;
$rec->{HANDLE}->autoflush(1);
$rec->{HANDLE}->print(" a string\n"); Объявление ХЭША СЛОЖНЫХ ЗАПИСЕЙ
my %TV = (
flintstones => {
series => "flintstones",
nights => [ qw(monday thursday friday) ],
members => [
{ name => "fred", role => "lead", age => 36, },
{ name => "wilma", role => "wife", age => 31, },
{ name => "pebbles", role => "kid", age => 4, },
],
},
jetsons => {
series => "jetsons",
nights => [ qw(wednesday saturday) ],
members => [
{ name => "george", role => "lead", age => 41, },
{ name => "jane", role => "wife", age => 39, },
{ name => "elroy", role => "kid", age => 9, },
],
},
simpsons => {
series => "simpsons",
nights => [ qw(monday) ],
members => [
{ name => "homer", role => "lead", age => 34, },
{ name => "marge", role => "wife", age => 37, },
{ name => "bart", role => "kid", age => 11, },
],
},
); Генерация ХЭША СЛОЖНЫХ ЗАПИСЕЙ
# reading from file
# this is most easily done by having the file itself be
# in the raw data format as shown above. perl is happy
# to parse complex data structures if declared as data, so
# sometimes it's easiest to do that
# here's a piece by piece build up
my $rec = {};
$rec->{series} = "flintstones";
$rec->{nights} = [ find_days() ];
my @members = ();
# assume this file in field=value syntax
while (<>) {
my %fields = split /[\s=]+/;
push @members, { %fields };
}
$rec->{members} = [ @members ];
# now remember the whole thing
$TV{ $rec->{series} } = $rec;
###########################################################
# now, you might want to make interesting extra fields that
# include pointers back into the same data structure so if
# change one piece, it changes everywhere, like for example
# if you wanted a {kids} field that was a reference
# to an array of the kids' records without having duplicate
# records and thus update problems.
###########################################################
foreach my $family (keys %TV) {
my $rec = $TV{$family}; # temp pointer
my @kids = ();
for my $person ( $rec->{members}->@* ) {
if ($person->{role} =~ /kid|son|daughter/) {
push @kids, $person;
}
}
# REMEMBER: $rec and $TV{$family} point to same data!!
$rec->{kids} = [ @kids ];
}
# you copied the array, but the array itself contains pointers
# to uncopied objects. this means that if you make bart get
# older via
$TV{simpsons}{kids}[0]{age}++;
# then this would also change in
print $TV{simpsons}{members}[2]{age};
# because $TV{simpsons}{kids}[0] and $TV{simpsons}{members}[2]
# both point to the same underlying anonymous hash table
# print the whole thing
foreach my $family ( keys %TV ) {
print "the $family";
print " is on during $TV{$family}{nights}->@*\n";
print "its members are:\n";
for my $who ( $TV{$family}{members}->@* ) {
print " $who->{name} ($who->{role}), age $who->{age}\n";
}
print "it turns out that $TV{$family}{lead} has ";
print scalar ( $TV{$family}{kids}->@* ), " kids named ";
print join (", ", map { $_->{name} } $TV{$family}{kids}->@* );
print "\n";
} Связи с базой данных
Вы не можете легко связать многоуровневую структуру данных (такую как хэш хэшей) с файлом dbm. Первая проблема заключается в том, что все, кроме GDBM и Berkeley DB, имеют ограничения по размеру, но помимо этого у вас также возникают проблемы с тем, как ссылки должны быть представлены на диске. Один экспериментальный модуль, который частично пытается решить эту проблему, — это модуль MLDBM. Проверьте ближайший сайт CPAN, как описано в perlmodlib, для исходного кода MLDBM.
СМОТРИТЕ ТАКЖЕ
perlref, perllol, perldata, perlobj
АВТОР
Tom Christiansen <tchrist@perl.com>
© 1993–2023 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.38.0/perldsc