Имеет ли неинициализированный хэш-ключ значение по умолчанию ноль в Perl?

у меня есть код Perl, подобный следующему:

# -- start --

my $res;

# run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

# -- stop --

ни в коем случае это $res никогда до перебора результатов запроса, но код работает просто отлично.

когда я помещаю операторы печати перед каждым значением, я получаю пробелы в обоих случаях, но если операторы печати приходят после применения инкремента, я получаю значение >= 1 в зависимости от того, сколько ресурсов IPv6 имеет организация.

мой вопрос в том, я понимаю, что это означает неинициализированный хэш-ключ в Perl автоматически имеет нулевое значение?

Извините, если это воспринимается как вопрос новичка, но я просто не знаком с такой конструкцией т. е. $hashref->{foo}->{bar}++ где значение еще не было явно присвоено $hashref->{foo}->{bar}. Заранее спасибо!

4 ответов


значение автоматически не равно нулю. Значение не определено изначально. Однако, если вы относитесь к нему как к числу (например, apply ++ к нему), то Perl рассматривает его как ноль. Если вы относитесь к нему как к строке (например, apply . к нему), затем Perl обрабатывает его как пустую строку.

С perldoc perlsyn в разделе 'Объявления':

единственное, что вам нужно объявить в Perl-это форматы отчетов и подпрограммы (а иногда даже не подпрограммы.) Переменная держит неопределенное значение ("undef"), пока оно не было присвоено определенное значение, которое это что-нибудь, кроме "undef". Когда используется как номер," undef " обрабатывается как 0; при использовании в качестве строки, это рассматривается как пустая строка,""; и при использовании в качестве ссылки, которая не будучи назначенным, он рассматривается как ошибка.


чтобы уточнить пост Телемаха, неинициализированные значения будут неопределенными. Глубокие части структуры autovivified. Это удобная функция, где структуры данных создаются автоматически. Самовоспроизведение прекрасно, когда вы этого хотите, но это может быть боль, когда вы хотите предотвратить это. Есть много учебников, статьи и сообщения по сети на понимание autovivification.

таким образом, учитывая неопределенный $ref и $ref->{ipv6}{pa}{'foo'}++, $ref будет присвоено значение:

$ref = { 
     ipv6 => { 
          pa => { 
              foo => undef
          }
     }
};

затем фдоон будет увеличиваться, поскольку фдоон numifies на 0, получаем 0++, которая 1. Для окончательного результата: ref->{ipv6}{pa}{'foo'} == 1.

если у вас включен режим предупреждения (вы use warnings;, не так ли?) при работе с этими неопределенными значениями вы получите предупреждение "неинициализированное значение". Если требуется увеличить значение unitialized, то можно отключить нужную группу предупреждений на ограниченной части код:

use strict;
use warnings;
my $res;

// run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{   no warnings 'uninitialized';
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

вы можете найти иерархию предупреждений в perllexwarn.


он в основном не определен, но рассматривается как ноль, когда вы его увеличиваете.

термин на языке Perl - "автовифицированный".

что вы, вероятно, хотите сделать, это использовать ключевое слово:

$res->{ipv6}{pa}{$row->[2]}++ if exists($res->{ipv6}{pa}{$row->[2]});

нет такой вещи, как неинициализированный хэш ключ. То, что может быть неинициализировано, - это стоимостью для определенного ключа. Хэш-значение - это просто скалярное значение; оно ничем не отличается от переменной типа $foo.

есть несколько различных функций Perl, взаимодействующих в вашем примере.

изначально $res неопределено (т. е. имеет значение undef). Когда вы используете неинициализированное значение в качестве хэш-ссылки (как в $res->{ipv6}...) Perl "autovivifies" это как один. То есть Perl создает анонимный хэш и заменяет значение undef со ссылкой на новый хэш. Этот процесс повторяется (молча) каждый раз, когда вы использовать полученное значение в качестве ссылки.

в конце концов, вы autovivify свой путь к $res->{ipv6}{pa}{$row->[2]}, который является неопределенным. Помните, что это просто скалярное значение типа $foo. Поведение то же самое, что сказать

my $foo;
$foo++;

Perl делает специальные вещи, когда вы используете undefined ценности. Если вы используете их как число, Perl преобразует их в 0. Если вы используете их как строку, Perl преобразует их в " (пустую строку). В большинстве случаев вы получите "использование неинициализированных значение..."предупреждение, если у вас включены предупреждения (которые вы должны). The автоинкремент оператор (++), это особый случай,. Для удобства он молча преобразует значение из undef to 0 прежде чем увеличивать его.