2009-08-29 8 views
8

Mam fragment w tej postaci:W Perlu, czy istnieje zgrabny sposób ręcznie przekonwertować undef na 0?

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; 

rzeczywistość jest jeszcze bardziej niechlujny, ponieważ więcej niż dwie zmienne są zainteresowane.

Co naprawdę chcę napisać to:

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

i nie undef prawidłowo ocenić na 0, ale pojawia się te ostrzeżenia w niemal każdym biegu:

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

Jaki jest najlepszy sposób, aby te wiadomości odejdą?

NB: Używam ścisłego "i" stosuj ostrzeżenia ", jeśli jest to istotne.

+0

Jest to istotne. W takim przypadku włączono ostrzeżenie, na które nie masz wpływu. – jrockway

Odpowiedz

16

To dobrze, że używasz strict i warnings. Celem ostrzeżeń jest ostrzeżenie, gdy Perl widzi zachowanie, które może być niezamierzone (a przez to nieprawidłowe). Kiedy robisz to celowo, dobrze jest wyłączyć ostrzeżenie lokalnie. undef jest traktowany jako 0 w kontekście numerycznym. Jeśli jesteś w porządku zarówno posiadające wartości niezdefiniowanych i posiadające je ocenić na zero, po prostu wyłączyć ostrzeżenie:

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

Uwaga: Wyłączenie tylko ostrzeżenia musisz, i to w możliwie najmniejszym zakresie.

Jeśli nie możesz wyłączyć ostrzeżeń, istnieją inne opcje. Od wersji Perl 5.10 można użyć operatora // (zdefiniowanego lub) do ustawienia wartości domyślnych. Wcześniej ludzie często używają || (logicznej lub), ale może to zrobić Wrong Thing dla wartości, które oceniają jako fałszywe. Solidnym sposobem na wartości domyślne w wersjach Perla wersji 5.10 jest sprawdzenie, czy są one defined.

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

Tak, "$ y || 42" jest kruchy, ale "$ y || 0" nie jest tak delikatny. – innaM

6

Możesz wyłączyć „niezainicjowanej” ostrzeżenie na sekundę:

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

lub można zwarcia do zera:

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

nie wygląda bardzo miły dla mnie jednak.

4

Podczas dodawania, po prostu odfiltruj tajniki.

use List::Util 'sum'; 

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

Albo nawet

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; 

W tym przypadku, to OK, aby traktować fałszywe wartości takie same jak wartości niezdefiniowanych powodu swojej wartości awaryjnej.

+1

Ten kod nie robi dokładnie tego samego. Zmienia także pusty łańcuch, zdefiniowaną wartość, na 0. To może nie być to, czego chcesz. –

+0

Zakładałem, że kiedy je dodawał, było to w rzeczywistości to, czego chciał. –

Powiązane problemy