Есть ли в Perl изящный способ конвертировать undef в 0 вручную? - PullRequest
8 голосов
/ 29 августа 2009

У меня есть фрагмент в этой форме:

my $a = $some_href->{$code}{'A'}; # a number or undef
my $b = $some_href->{$code}{'B'}; # a number or undef
$a = 0 unless defined($a);
$b = 0 unless defined($b);
my $total = $a + $b;

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

Что я действительно хочу написать, это:

my $total = $some_href->{$code}{'A'} + $some_href->{$code}{'B'};

и undef правильно оценивается как 0, но я получаю эти предупреждения почти при каждом запуске:

Use of uninitialized value in addition (+) at Stats.pm line 192.

Какой лучший способ заставить эти сообщения исчезнуть?

Примечание: я «использую строгие» и «использую предупреждения», если это уместно.

Ответы [ 4 ]

16 голосов
/ 29 августа 2009

Хорошо, что вы используете strict и warnings. Цель предупреждений - предупредить вас, когда Perl видит поведение, которое может быть непреднамеренным (и, следовательно, неправильным). Когда вы делаете это намеренно, вполне нормально отключить предупреждение локально. undef трактуется как 0 в числовом контексте. Если у вас все в порядке с неопределенными значениями и их значением, равным нулю, просто отключите предупреждение:

my $total;
{
  no warnings 'uninitialized';
  $total = $some_href->{$code}{A} + $some_href->{$code}{B};
}

Примечание. Отключайте только те предупреждения, которые вам нужны, и делайте это в наименьшем объеме.

Если вы не хотите отключать предупреждения, есть и другие варианты. Начиная с Perl 5.10, вы можете использовать оператор // (определенный-или) для установки значений по умолчанию. До этого люди часто использовали || (логическое или), но это может сделать неправильную вещь для значений, которые оцениваются как ложные. Надежный способ установить значения по умолчанию в версиях Perl до 5.10 - это проверить, являются ли они defined.

$x = $y // 42;             # 5.10+
$x = $y || 42;             # < 5.10 (fragile)
$x = defined $y ? $y : 42; # < 5.10 (robust)
6 голосов
/ 29 августа 2009

Вы можете отключить «неинициализированное» предупреждение на секунду:

my $a;
my $b = 1;
{
    no warnings 'uninitialized';
    my $c = $a+$b; # no warning
}
my $c = $a+$b; # warning

Или вы можете замкнуть на ноль:

my $d = ($a||0)+$b; # no warning

Мне не очень приятно.

4 голосов
/ 29 августа 2009
my $a = $some_href->{$code}{'A'} || 0;
my $b = $some_href->{$code}{'B'} || 0;
my $total = $a + $b;

В этом случае можно рассматривать ложные значения так же, как неопределенные, из-за вашего запасного значения.

4 голосов
/ 29 августа 2009

Когда вы добавляете их, просто отфильтруйте undefs.

use List::Util 'sum';

my $total = sum (0, grep {defined} $some_href->{$code}{'A'}, $some_href->{$code}{'B'});

Или даже

use List::Util 'sum';

my $total = sum (0, grep {defined} map {$some_href->{$code}{$_}} 'A', 'B');
...