2009-08-29 11 views
8

Ho un frammento in questa forma:In Perl, c'è un modo elegante per convertire undef a 0 manualmente?

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 hanno 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 'use strict' e 'use warnings', se pertinente.

+0

È pertinente. In questo caso, hai attivato un avviso di cui non ti importa. – jrockway

risposta

16

È opportuno utilizzare strict e warnings. Lo scopo degli avvertimenti è di avvisarti quando Perl vede un comportamento che potrebbe non essere intenzionale (e quindi errato). Quando lo fai deliberatamente, è perfettamente corretto disattivare l'avviso localmente. undef viene considerato 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 dovete, e di farlo nel più piccolo ambito possibile.

Se non si desidera disabilitare gli avvisi, ci sono altre opzioni. A partire da Perl 5.10 è possibile utilizzare l'operatore // (definito o) per impostare i valori predefiniti. Prima di questo, le persone usano spesso lo || (logico o), ma questo può fare la cosa sbagliata per valori che valutano come falsi. Il metodo solido per i valori predefiniti nelle versioni precedenti a 5.10 di Perl è di verificare se sono defined.

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

Sì, "$ y || 42" è fragile, ma "$ y || 0" non è così fragile. – innaM

6

È 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 

Oppure è possibile corto circuito a zero:

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

non ha un aspetto molto bello per me però.

4

Come si aggiungono, basta filtrare gli 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'); 
4
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 fallback.

+1

Questo codice non fa esattamente la stessa cosa. Trasforma anche la stringa vuota, un valore definito, in 0. Potrebbe non essere quello che vuoi. –

+0

Ho pensato che, come li stava aggiungendo, era in effetti ciò che voleva. –

Problemi correlati