Spec-Zone.ru › Perl 5.36

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. Вкратце, ссылки похожи на указатели, которые знают, на что они указывают. (Объекты также являются типом ссылки, но нам пока не нужны - если вообще нужны). Это означает, что когда у вас есть то, что кажется вам доступом к двумерному или многомерному массиву и/или хэшу, на самом деле происходит то, что базовый тип представляет собой просто одномерную сущность, содержащую ссылки на следующий уровень. Просто можно использовать его как будто это двумерный.

$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() больше похоже на оператор во время выполнения, чем на объявление во время компиляции per se. Это означает, что переменная 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–2021 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.36.0/perldsc

Spec-Zone.ru

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