Неинициализированный хеш-ключ имеет значение по умолчанию ноль в Perl? - PullRequest
8 голосов
/ 01 мая 2009

У меня 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 ]

26 голосов
/ 01 мая 2009

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

С perldoc perlsyn, под «Декларации»:

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

5 голосов
/ 01 мая 2009

Чтобы уточнить пост Телемаха, неинициализированные значения будут неопределенными. Глубокие части структуры авививифицированы . Это удобная функция, где структуры данных создаются для вас автоматически. Автовификация хороша, когда вы этого хотите, но это может быть болезненно, если вы хотите предотвратить это. В сети много учебников, статей и постов по пониманию автовивификации.

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

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

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

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

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 .

4 голосов
/ 01 мая 2009

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

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

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

$res->{ipv6}{pa}{$row->[2]}++ if exists($res->{ipv6}{pa}{$row->[2]});
2 голосов
/ 01 мая 2009

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

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

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

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

my $foo;
$foo++;

Perl делает особые вещи, когда вы используете неопределенные значения. Если вы используете их как число, Perl преобразует их в 0. Если вы используете их как строку, Perl преобразует их в '' (пустая строка). В большинстве случаев вы получите предупреждение «Использовать неинициализированное значение ...», если у вас включены предупреждения (что вам следует). Однако оператор с автоинкрементом (++) является особым случаем. Для удобства он тихо преобразует значение из undef в 0 перед его увеличением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...