Em Perl, existe uma maneira elegante de converter undef em 0 manualmente?

StackOverflow https://stackoverflow.com/questions/1351103

  •  20-09-2019
  •  | 
  •  

Pergunta

Eu tenho um fragmento neste formato:

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;

A realidade é ainda mais confusa, uma vez que estão em causa mais de duas variáveis.

O que eu realmente quero escrever é isto:

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

e undef foi avaliado corretamente como 0, mas recebo esses avisos em quase todas as execuções:

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

Qual é a melhor maneira de fazer essas mensagens desaparecerem?

Observação:Eu 'uso estrito' e 'uso avisos' se isso for relevante.

Foi útil?

Solução

Que bom que você está usando strict e warnings.O objetivo dos avisos é alertá-lo quando Perl vê um comportamento que provavelmente não é intencional (e, portanto, incorreto).Quando você faz isso deliberadamente, é perfeitamente normal desativar o aviso localmente. undef é tratado como 0 em contextos numéricos.Se você concorda em ter valores indefinidos e avaliá-los como zero, apenas desative o aviso:

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

Observação:Desative apenas os avisos necessários e faça-o no menor escopo possível.

Se você não gosta de desativar avisos, existem outras opções.A partir do Perl 5.10 você pode usar o // Operador (definido ou) para definir valores padrão.Antes disso, as pessoas costumavam usar o || (lógico-ou), mas isso pode fazer a coisa errada para valores avaliados como falsos.A maneira robusta de definir valores padrão em versões anteriores à 5.10 do Perl é verificar se eles estão defined.

$x = $y // 42;             # 5.10+
$x = $y || 42;             # < 5.10 (fragile)
$x = defined $y ? $y : 42; # < 5.10 (robust)

Outras dicas

Você pode desligar o aviso “não inicializado” por um segundo:

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

Ou você pode entrar em curto-circuito para zero:

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

Mas não parece muito legal para mim.

Ao adicioná-los, basta filtrar os undefs.

use List::Util 'sum';

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

Ou mesmo

use List::Util 'sum';

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

Nesse caso, não há problema em tratar valores falsos da mesma forma que valores indefinidos por causa do seu valor substituto.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top