Spec-Zone.ru › Perl 5.28

perldsc

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • ОПИСАНИЕ
  • СПИСКИ ЛИТЕРАТУРЫ
  • ОБЩИЕ ОШИБКИ
  • ЗАМЕЧАНИЕ О ПРИОРИТЕТЕ
  • ПОЧЕМУ ВЫ ДОЛЖНЫ ВСЕГДА ИСПОЛЬЗОВАТЬ strict
  • ОТЛАДКА
  • ПРИМЕРЫ КОДА
  • МАССИВЫ МАССИВОВ
    • Объявление МАССИВА МАССИВОВ
    • Генерация МАССИВА МАССИВОВ
    • Доступ и вывод МАССИВА МАССИВОВ
  • ХЭШИ МАССИВОВ
    • Объявление ХЭША МАССИВОВ
    • Генерация ХЭША МАССИВОВ
    • Доступ и вывод ХЭША МАССИВОВ
  • МАССИВЫ ХЭШЕЙ
    • Объявление МАССИВА ХЭШЕЙ
    • Генерация МАССИВА ХЭШЕЙ
    • Доступ и вывод МАССИВА ХЭШЕЙ
  • ХЭШИ ХЭШЕЙ
    • Объявление ХЭША ХЭШЕЙ
    • Генерация ХЭША ХЭШЕЙ
    • Доступ и вывод ХЭША ХЭШЕЙ
  • БОЛЕЕ СЛОЖНЫЕ СТРУКТУРЫ
    • Объявление БОЛЕЕ СЛОЖНЫХ СТРУКТУР
    • Объявление ХЭША СЛОЖНЫХ СТРУКТУР
    • Генерация ХЭША СЛОЖНЫХ СТРУКТУР
  • Связи с базой данных
  • СМОТРИТЕ ТАКЖЕ
  • АВТОР

НАЗВАНИЕ

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 ];     # usually best
$AoA[$i] = \@array;        # perilous; just how my() was that array?
@{ $AoA[$i] } = @array;    # way too tricky for most programmers

ЗАМЕЧАНИЕ О ПРИОРИТЕТЕ

Говоря о таких вещах, как @{$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]} , чтобы заставить $AoA[$i] быть вычисленным первым перед ведущим $ разыменователем.

ПОЧЕМУ ВЫ ДОЛЖНЫ ВСЕГДА use strict

Если это начинает звучать страшнее, чем того стоит, успокойтесь. Perl имеет некоторые функции, которые помогут вам избежать самых распространенных ловушек. Лучший способ избежать путаницы – начать каждую программу так:

#!/usr/bin/perl -w
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]

ОТЛАДКА

Вы можете использовать команду отладчика 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'

ПРИМЕРЫ КОДА

Представленные с небольшими комментариями (они получат свои страницы справки в будущем) вот короткие примеры кода, иллюстрирующие доступ к различным типам структур данных.

МАССИВЫ МАССИВОВ

Объявление МАССИВА МАССИВОВ

@AoA = (
       [ "fred", "barney" ],
       [ "george", "jane", "elroy" ],
       [ "homer", "marge", "bart" ],
     );

Генерация МАССИВА МАССИВОВ

# reading from file
while ( <> ) {
    push @AoA, [ split ];
}

# calling a function
for $i ( 1 .. 10 ) {
    $AoA[$i] = [ somefunc($i) ];
}

# using temp vars
for $i ( 1 .. 10 ) {
    @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 $aref ( @AoA ) {
    print "\t [ @$aref ],\n";
}

# print the whole thing with indices
for $i ( 0 .. $#AoA ) {
    print "\t [ @{$AoA[$i]} ],\n";
}

# print the whole thing one at a time
for $i ( 0 .. $#AoA ) {
    for $j ( 0 .. $#{ $AoA[$i] } ) {
        print "elt $i $j is $AoA[$i][$j]\n";
    }
}

ХЭШИ МАССИВОВ

Объявление ХЭША МАССИВОВ

%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 ( $line = <> ) {
    ($who, $rest) = split /:\s*/, $line, 2;
    @fields = split ' ', $rest;
    $HoA{$who} = [ @fields ];
}

# calling a function that returns a list
for $group ( "simpsons", "jetsons", "flintstones" ) {
    $HoA{$group} = [ get_family($group) ];
}

# likewise, but using temps
for $group ( "simpsons", "jetsons", "flintstones" ) {
    @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 $family ( keys %HoA ) {
    print "$family: @{ $HoA{$family} }\n"
}

# print the whole thing with indices
foreach $family ( keys %HoA ) {
    print "family: ";
    foreach $i ( 0 .. $#{ $HoA{$family} } ) {
        print " $i = $HoA{$family}[$i]";
    }
    print "\n";
}

# print the whole thing sorted by number of members
foreach $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 $family ( sort {
                           @{$HoA{$b}} <=> @{$HoA{$a}}
                                       ||
                                   $a cmp $b
           } keys %HoA )
{
    print "$family: ", join(", ", sort @{ $HoA{$family} }), "\n";
}

МАССИВЫ ХЭШЕЙ

Объявление МАССИВА ХЭШЕЙ

@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 ( <> ) {
    $rec = {};
    for $field ( split ) {
        ($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 ( %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 $href ( @AoH ) {
    print "{ ";
    for $role ( keys %$href ) {
        print "$role=$href->{$role} ";
    }
    print "}\n";
}

# print the whole thing with indices
for $i ( 0 .. $#AoH ) {
    print "$i is { ";
    for $role ( keys %{ $AoH[$i] } ) {
        print "$role=$AoH[$i]{$role} ";
    }
    print "}\n";
}

# print the whole thing one at a time
for $i ( 0 .. $#AoH ) {
    for $role ( keys %{ $AoH[$i] } ) {
        print "elt $i $role is $AoH[$i]{$role}\n";
    }
}

ХЭШИ ХЭШЕЙ

Объявление ХЭША ХЭШЕЙ

%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*//;
    $who = $1;
    for $field ( split ) {
        ($key, $value) = split /=/, $field;
        $HoH{$who}{$key} = $value;
    }


# reading from file; more temps
while ( <> ) {
    next unless s/^(.*?):\s*//;
    $who = $1;
    $rec = {};
    $HoH{$who} = $rec;
    for $field ( split ) {
        ($key, $value) = split /=/, $field;
        $rec->{$key} = $value;
    }
}

# calling a function  that returns a key,value hash
for $group ( "simpsons", "jetsons", "flintstones" ) {
    $HoH{$group} = { get_family($group) };
}

# likewise, but using temps
for $group ( "simpsons", "jetsons", "flintstones" ) {
    %members = get_family($group);
    $HoH{$group} = { %members };
}

# append new members to an existing family
%new_folks = (
    wife => "wilma",
    pet  => "dino",
);

for $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 $family ( keys %HoH ) {
    print "$family: { ";
    for $role ( keys %{ $HoH{$family} } ) {
        print "$role=$HoH{$family}{$role} ";
    }
    print "}\n";
}

# print the whole thing  somewhat sorted
foreach $family ( sort keys %HoH ) {
    print "$family: { ";
    for $role ( sort keys %{ $HoH{$family} } ) {
        print "$role=$HoH{$family}{$role} ";
    }
    print "}\n";
}


# print the whole thing sorted by number of members
foreach $family ( sort { keys %{$HoH{$b}} <=> keys %{$HoH{$a}} }
                                                            keys %HoH )
{
    print "$family: { ";
    for $role ( sort keys %{ $HoH{$family} } ) {
        print "$role=$HoH{$family}{$role} ";
    }
    print "}\n";
}

# establish a sort order (rank) for each role
$i = 0;
for ( qw(lead wife son daughter pal pet) ) { $rank{$_} = ++$i }

# now print the whole thing sorted by number of members
foreach $family ( sort { keys %{ $HoH{$b} } <=> keys %{ $HoH{$a} } }
                                                            keys %HoH )
{
    print "$family: { ";
    # and print these according to rank order
    for $role ( sort { $rank{$a} <=> $rank{$b} }
                                              keys %{ $HoH{$family} } )
    {
        print "$role=$HoH{$family}{$role} ";
    }
    print "}\n";
}

БОЛЕЕ СЛОЖНЫЕ ЗАПИСИ

Объявление БОЛЕЕ СЛОЖНЫХ ЗАПИСЕЙ

Вот пример, показывающий, как создать и использовать запись, поля которой имеют различные типы:

$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];
$last = pop @ { $rec->{SEQUENCE} };

print $rec->{LOOKUP}{"key"};
($first_k, $first_v) = each %{ $rec->{LOOKUP} };

$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");

Объявление ХЭША СЛОЖНЫХ ЗАПИСЕЙ

%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
$rec = {};
$rec->{series} = "flintstones";
$rec->{nights} = [ find_days() ];

@members = ();
# assume this file in field=value syntax
while (<>) {
    %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 $family (keys %TV) {
    $rec = $TV{$family}; # temp pointer
    @kids = ();
    for $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 $family ( keys %TV ) {
    print "the $family";
    print " is on during @{ $TV{$family}{nights} }\n";
    print "its members are:\n";
    for $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–2020 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.28.3/perldsc

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API