Неинициализированный хеш-ключ имеет значение по умолчанию ноль в Perl?
-
03-07-2019 - |
Вопрос
У меня есть 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}
. Заранее спасибо!
Решение
Значение не равно нулю автоматически. Значение не определено изначально. Однако, если вы рассматриваете его как число (например, применяете к нему ++
), то Perl обрабатывает его как ноль. Если вы рассматриваете его как строку (например, применяете к нему .
), то Perl обрабатывает его как пустую строку.
Из perldoc perlsyn
в разделе «Объявления»:
Единственное, что вам нужно объявить в Perl - это форматы отчетов и подпрограммы (а иногда даже не Подпрограммы). Переменная содержит неопределенное значение (" undef "), пока оно не было назначено определенное значение, которое является чем-то иным, чем "undef". когда используется в качестве числа "undef" лечится как 0; когда используется как строка, это рассматривается как пустая строка, " " ;; а также при использовании в качестве эталона, который не является & # 8217; т будучи назначенным, он рассматривается как ошибка.
Другие советы
Чтобы уточнить пост Телемаха, неинициализированные значения будут неопределенными. Глубокие части структуры автоматически оживлены . Это удобная функция, где структуры данных создаются для вас автоматически. Автовификация хороша, когда вы этого хотите, но это может быть болезненно, если вы хотите предотвратить это. В сети много учебников, статей и постов по пониманию автовивификации.
Так, учитывая неопределенные $ ref
и $ ref- > {ipv6} {pa} {'foo'} ++
, $ ref Коду> будет присвоено значение:
$ref = {
ipv6 => {
pa => {
foo => undef
}
}
};
Тогда undef будет увеличен, поскольку undef нумерует до 0, мы получаем 0 ++, который равен 1.
Окончательный результат: ref- > {ipv6} {pa} {'foo'} == 1
.
Если у вас включены предупреждения (вы используете предупреждения;
, не так ли?), вы получите " неинициализированное значение " предупреждение при работе с этими неопределенными значениями. Если требуется увеличить значение унитарной величины, то вы можете отключить нужную группу предупреждений для ограниченной части вашего кода:
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 " autovivizes " это как один. То есть Perl создает анонимный хеш и заменяет значение undef
ссылкой на новый хеш. Этот процесс повторяется (тихо) каждый раз, когда вы используете результирующее значение в качестве ссылки.
В конце концов, вы автоматически выбираете путь к $ res- > {ipv6} {pa} {$ row- > [2]}
, который не определен. Помните, что это просто скалярное значение, например $ foo
. Поведение такое же, как сказать
my $foo;
$foo++;
Perl делает особые вещи, когда вы используете неопределенные значения. Если вы используете их как число, Perl преобразует их в 0. Если вы используете их как строку, Perl преобразует их в '' (пустая строка). В большинстве случаев вы получите " Использование неинициализированного значения ... " предупреждение, если у вас включены предупреждения (что вы должны). оператор автоматического увеличения ( + +
) это особый случай. Для удобства он тихо преобразует значение из undef
в 0
перед его увеличением.