In Perl, c'è modo aggraziato per convertire undef a 0 manualmente?
Domanda
Ho un frammento in questa forma:
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;
La realtà è ancora più disordinato, da più di due variabili sono interessati.
Quello che voglio scrivere è questo:
my $total = $some_href->{$code}{'A'} + $some_href->{$code}{'B'};
e ho undef valutare correttamente a 0 ma ottengo questi avvertimenti in quasi ogni corsa:
Use of uninitialized value in addition (+) at Stats.pm line 192.
Qual è il modo migliore per rendere questi messaggi vanno via?
NB: I 'usare severe' e 'Usa avvertimenti' Se questo è rilevante
.Soluzione
E 'bene che si sta utilizzando e strict
warnings
. Lo scopo di avvertimenti è quello di avvisare l'utente quando Perl vede un comportamento che è probabile che sia non intenzionale (e quindi non corretta). Quando si sta facendo volutamente, è perfettamente bene per disattivare l'avviso a livello locale. undef
viene trattato come 0
in contesti numerici. Se stai bene con entrambi che hanno valori non definiti e di farle valutare a zero, basta disattivare l'avviso:
my $total;
{
no warnings 'uninitialized';
$total = $some_href->{$code}{A} + $some_href->{$code}{B};
}
. Nota: Disattivare solo gli avvertimenti che è necessario, e di farlo nel più piccolo ambito possibile
Se siete contrari alla disattivazione di avvertimenti, ci sono altre opzioni. A partire dal Perl 5.10 è possibile utilizzare il //
(definita o) all'operatore di impostare i valori predefiniti. Prima che le persone usano spesso la ||
(logico-o), ma che può fare la cosa sbagliata per i valori che restituiscono falso. Il modo robusto ai valori di default in pre-5.10 versioni di Perl è quello di verificare se sono defined
.
$x = $y // 42; # 5.10+
$x = $y || 42; # < 5.10 (fragile)
$x = defined $y ? $y : 42; # < 5.10 (robust)
Altri suggerimenti
È possibile disattivare l'avviso “non inizializzato” per un secondo:
my $a;
my $b = 1;
{
no warnings 'uninitialized';
my $c = $a+$b; # no warning
}
my $c = $a+$b; # warning
In alternativa, è possibile corto circuito a zero:
my $d = ($a||0)+$b; # no warning
Non sembra molto bello per me però.
Come li sta aggiungendo, basta filtrare i undefs.
use List::Util 'sum';
my $total = sum (0, grep {defined} $some_href->{$code}{'A'}, $some_href->{$code}{'B'});
O anche
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;
In questo caso, va bene per il trattamento di falsi valori lo stesso di valori non definiti a causa del vostro valore di sicurezza.