Perl — анонимные хэш-карты и массивы — несколько вопросов

Здравствуйте, я изучаю perl и опубликую здесь несколько предположений. Поэтому, пожалуйста, не стесняйтесь комментировать и исправлять меня, если я где-то ошибаюсь.

  1. Создание хэша выполняется (среди нескольких других способов):

    %numbers = qw(one 1 two 2);
    
  2. Создание массива выполняется следующим образом:

    @array = qw(one two);
    
  3. Вышеуказанные конструкции представляют «неанонимные» типы. Основное различие между неанонимными и анонимными типами заключается в том, что именованные типы имеют имя, на которое я могу ссылаться. Если я хочу создать анонимные типы, мне нужно изменить скобки () на квадратные скобки [] в массивах или на фигурные скобки {} в хэшах. Другими словами, хеш хэшей — это хэш ссылок на другие хэши. Таким образом, мне нужно использовать {} во вложенном хэше, а не классический хэш ().

    %HoH = (
        flintstones => {
            husband   => "fred",
            pal       => "barney",
        },
        jetsons => {
            husband   => "george",
            wife      => "jane",
            "his boy" => "elroy",  # quotes needed on key.
        },
        simpsons => {
            husband   => "homer",
            wife      => "marge",
            kid       => "bart",
        },
    );
    
  4. То же самое относится и к многомерным массивам. Многомерный массив — это массив, содержащий ссылки на другой массив, поэтому вместо него необходимо использовать [] ().

    @array_of_arrays =  ( [ "one", "two", "three" ],
                          [  4,   5,  6,  7  ],
                          [ "alpha", "beta" ]
                        );
    
  5. Если бы у меня были «неанонимные» хэши, содержащие каждого члена семьи (флинстоуны, джетсоны, симпсоны), какую конструкцию я должен использовать для создания %HOH?

    $HOH{flinstones} = {%flinstones};
    

    or

    $HOH{flinstones} = \%flinstones;
    

    Я предполагаю, что \%flinstones просто присваивает ссылку на $HOH{flinstones}, это означает, что все, что я делаю с %flinstones, повлияет на $HOH{flinstones}, поскольку оно просто содержит ссылку на него. С другой стороны, {%flinstones} — это что-то вроде преобразования «неанонимного» хэша в «анонимный». Это приводит к тому, что %flinstones можно позже изменить или даже удалить, и это не повлияет на $HOH{flinstones}, поскольку есть ссылка на анонимный хэш.

  6. Что произойдет с переменной в цикле? Когда my $variable; выдается внутри цикла, он перезаписывает старый или создает новый, или это одна и та же переменная, или что здесь происходит?

    for($i=0;$i<4;$i++){
      my $variable=$i;
      print $variable
    }
    

person Wakan Tanka    schedule 12.03.2013    source источник
comment
Вы должны задавать только один вопрос на вопрос.   -  person TLP    schedule 12.03.2013


Ответы (3)


Я называю их "литеральный хэш", "литеральный массив", но каждому свое.

Вы должны знать, что в Perl — за исключением случая ties— [...] и \@x довольно почти то же самое. И эти {...} и \%h тоже. Они оба «конструируют» ссылки на массивы и хэши.

В вопросе 5 оба будут делать то, что вы хотите. Но можно сделать это более эффективно. Во втором примере ссылка на уже определенный хеш хранится как значение в другом хеше. Первый пример,

$HOH{flinstones} = {%flinstones}

создает хэш для возврата адреса и расширяется %flintstones в список в соответствии с контекстом списка. Таким образом, он сохраняет хэш, являющийся точной копией %flintstones, в отдельном хэше, хранящемся в %HOH. Вы правы, изменения в %flintstones не повлияют на эту копию.

Вот небольшой совет для вас. Установите, Smart::Comments (SC), создайте несколько тестовых сценариев и просто загрузите внутренние переменные через СТДЕРР. Вы будете поражены тем, насколько больше вы можете узнать, видя внутренности всего, что вы хотите увидеть.

Вот несколько уроков из моего опыта работы с SC:

  • установите $Data::Dumper::Maxdepth в некоторое положительное целочисленное значение, если вы собираетесь выгружать Win32::OLE объектов, так как каждая ссылка на один и тот же объект OLE может выглядеть как другой объект Perl при обходе.

  • Никогда не сбрасывайте $_ сам по себе. По какой-то причине код в SC может его изменить. Поэтому всегда делайте что-то вроде этого:

    my $a = $_;
    ### $_ : $a
    
  • Дескрипторы ввода-вывода не сбрасываются, так что не пытайтесь. Используйте строку по умолчанию.

Теперь, наконец, если бы вы не выгрузили %flintstones с %HOH, у вас не было бы возможности узнать — с помощью простого дампа переменной — одинаковы ли ссылки или нет. Однако помните, что вы можете установить $Data::Dumper::Maxdepth, чтобы не получить полный дамп. Таким образом, вы можете проверить, были ли две ссылки одинаковыми, частично выгрузив их и используя прямую классическую строковую классификацию ссылок Perl.

### %flintstones : '' . \%flintstones 
local $Data::Dumper::Maxdepth = 1;
### %HOH

Если вы сами увидите, в чем дело, это поможет вам изучить Perl быстрее, чем задавать кучу вопросов на Stackoverflow.

person Axeman    schedule 12.03.2013

Что касается вопроса 5, который, как я предполагаю, является вопросом 1, вы можете использовать оба. Хотя вы должны понимать, что первый способ:

$HOH{flinstones} = {%flinstones}

Просто делает неглубокую копию хэша %flinstones, где он расширяется до списка его ключей и значений. В то время как

$HOH{flinstones} = \%flinstones

Передает хэш в качестве ссылки, так что оба хэша указывают на одно и то же место в памяти.

Что касается вопроса 6, что происходит с переменной с лексической областью видимости? Давайте посмотрим на perldoc -f my:

A "my" declares the listed variables to be local (lexically) to
the enclosing block, file, or "eval".

Цикл for — это блок, что означает, что любая переменная, объявленная с помощью my внутри цикла for, является локальной для этого цикла и локальной для каждой итерации этого цикла. Это означает, что если вы сделаете что-то вроде этого:

for my $number (0 .. 3) {
    print "Number is $_. Last number was $last\n";
    my $last = $_;                       # WRONG!
}   # $last goes out of scope here!

Это даст вам много Use of uninitialized value предупреждений. Вам нужно расширить область действия:

my $last = "N/A";  # default value
for my $number (0 .. 3) {
    print "Number is $_. Last number was $last\n";
    $last = $_;
}

Я не знаю, было ли это намеренно с вашей стороны, но вы можете объединить оба этих вопроса в один:

my %HOH;
{ # begin a block to reduce scope of variables
    my %flinstones = (
        husband   => "fred",
        pal       => "barney",
    );
    $HOH{flinstones} = \%flinstones;
} 
... # %flinstones hash is now out of scope, stored only in %HOH
person TLP    schedule 12.03.2013

Конструкция { LIST } принимает список значений и строит из них анонимный хэш ( точно так же, как если бы вы присвоили тот же список именованному хешу с помощью %hash = (LIST)) и вернули ссылку на этот хеш.

В «анонимных хэшах» в Perl нет ничего особенного: это обычные хэши, как и любые другие. Единственное, что делает их «анонимными», это то, что у них (в настоящее время) нет имени, поэтому вы можете ссылаться на них только по ссылке.

Привязка к имени переменной также не является неотъемлемым свойством хэшей: вполне возможно, что именованный хэш станет анонимным (например, если имя, которое у него было, выходит за пределы области видимости) или даже анонимный хеш получит имя через манипулирование таблицей символов, например:

my $hashref = {foo => 'bar'};
our %hash;             # required by "use strict"
*hash = $hashref;
print "$hash{foo}\n";  # prints "bar"

После строки *hash = $hashref глобальная переменная %hash становится новым именем для хэша, на который указывает ссылка $hashref, независимо от того, было ли у него уже имя раньше или нет. Этот механизм даже позволяет одному и тому же хэшу иметь более одного имени: на самом деле, любой модуль Perl, который позволяет вам экспортировать хеш (или любую другую переменную) из своего собственного пространства имен в ваше, по сути, делает именно это под капотом.

Разумеется, все сказанное относится и к массивам (да и к скалярам тоже) точно так же.


Что касается вашего последнего вопроса, my на самом деле создает новую переменную с лексической областью видимости каждый раз, когда она выполняется, вместо того, чтобы каждый раз повторно использовать одну и ту же переменную. На самом деле это не имеет никакого значения для кода вашего примера, но одна ситуация, когда это будет иметь значение, — это если вы сохранили ссылку на переменную до того, как она вышла из области видимости. Например, ниже приведен довольно распространенный способ преобразования данных, разделенных символами табуляции, в массив:

my @table;
while (my $line = <>) {
    chomp $line;
    my @row = split /\t/, $line;
    # maybe do some manipulation or checks on @row here...
    push @table, \@row;
}

Если вы проверите это, вы обнаружите, что этот код действительно заполняет @table ссылками на разные (теперь анонимные) массивы для каждой строки, а не многими ссылками, указывающими на один и тот же массив.

person Ilmari Karonen    schedule 12.03.2013