2012-01-07 8 views
10

Gdzie jest niezainicjowana wartość w the below code?Gdzie pojawia się błąd "Wykorzystanie niezainicjowanej wartości w ciągu ne"?

#!/usr/bin/perl 
use warnings; 

my @sites = (undef, "a", "b"); 
my $sitecount = 1; 
my $url; 

while (($url = $sites[$sitecount]) ne undef) { 
    $sitecount++; 
} 

wyjściowa:

Use of uninitialized value in string ne at t.pl line 6. 
Use of uninitialized value in string ne at t.pl line 6. 
Use of uninitialized value in string ne at t.pl line 6. 
Use of uninitialized value in string ne at t.pl line 6. 
+0

I: Z góry dzięki – 11684

+0

Mat: dzięki za wyróżnienie – 11684

+0

Na czym polega pytanie? –

Odpowiedz

18

Nie można używać undef w porównaniu ciąg bez ostrzeżenia.

if ("a" ne undef) { ... } 

spowoduje wyświetlenie ostrzeżenia. Jeśli chcesz sprawdzić, czy zmienna jest zdefiniowana lub nie, użyj:

if (defined $var) { ... } 

Komentarze o oryginalnym pytanie:

To dziwny sposób iteracyjne nad tablicę. Im bardziej zwykły sposób w ten sposób byłoby:

foreach my $url (@sites) { ... } 

i upuść zmienną $sitecount całkowicie, a nie zastępować $url w ciele pętli. Zmniejsz także wartość undef w tej tablicy. Jeśli nie chcesz, aby usunąć ten undef z jakiegoś powodu (lub oczekiwać wartości niezdefiniowane do włożenia w nie), można zrobić:

foreach my $url (@sites) { 
    next unless defined $url; 
    ... 
} 

Jeśli chcesz przetestować niezdefiniowane z postaci pętli konstruktem , to trzeba:

while (defined $sites[$sitecount]) { 
    my $url = $sites[$sitecount]; 
    ... 
    $sitecount++; 
} 

uniknąć ostrzeżenia, ale uważaj autovivification, a pętla zatrzyma krótki jeśli masz undef s mieszane między innymi wartościami żywo.

+0

Właśnie wstawiłem "undef", ponieważ myślałem, że "$ sitecount = 0" może być interpretowane jako niezainicjowane. Thx – 11684

+0

Dlaczego nie mogę teraz przyjąć tej odpowiedzi? – 11684

+0

@strange sposób iterować: W PHP działa, a system zmiennych wygląda w większości tak samo, więc pomyślałem, że to zadziała ... – 11684

3

ne jest dla porównania ciągów i undef nie jest ciągiem:

#!/usr/bin/perl 
use warnings; 
('l' ne undef) ? 0 : 0; 

Wykorzystanie wartości niezainicjowanych w ciąg ne na linii t.pl 3.

Czyni pracę, ale pojawia się [nieco mylące] ostrzeżenie (przynajmniej z use warnings), ponieważ undef nie jest "wartością początkową" dla ne do użycia.


Zamiast use the operator defined to find whether a value is defined:

#!/usr/bin/perl 
use warnings; 

my @sites = (undef, "a", "b"); 
my $sitecount = 1; 
my $url; 

while (defined $sites[$sitecount]) { # <---------- 
    $url = $sites[$sitecount]; 
    # ... 
    $sitecount++; 
} 

... lub pętli nad tablicy @sites bardziej konwencjonalnie, jak Mat bada w swojej odpowiedzi.

5

Być może wiadomość byłoby lepiej zrozumieć, czy to:

You are trying to compare an uninitialized value with a string. 

Wartość niezainicjowany jest, oczywiście, undef.

Aby jawnie sprawdzić czy $something jest zdefiniowana, trzeba napisać

defined $something 
6

Prawidłowe odpowiedzi zostały już podane (defined sposób można sprawdzić wartość definedness), ale chciałem coś dodać.

W perlop będziesz czytać ten opis ne:

Binary „ne” zwraca prawdę, jeśli lewy argument nie jest łańcuchowo równy do prawego argumentu.

Zwróć uwagę na użycie "stringwise". Zasadniczo oznacza to, że podobnie jak w przypadku innych operatorów, takich jak ==, gdzie typ argumentu jest wstępnie zdefiniowany, wszelkie argumenty do ne zostaną skutecznie przekonwertowane na ciągi przed wykonaniem operacji. Ma to na celu pomieścić operacje, takie jak:

if ($foo == "1002") # string "1002" is converted to a number 
if ($foo eq 1002) # number 1002 is converted to a string 

Perl nie ma stałego typy danych, a polega na konwersji danych. W tym przypadku, undef (który przypadkowo nie jest wartością, jest to funkcja: undef(), która zwraca niezdefiniowaną wartość), jest konwertowana na ciąg znaków. Ta konwersja spowoduje fałszywe alarmy, które mogą być trudne do wykrycia, jeśli warnings nie będzie działać.

Rozważmy:

perl -e 'print "" eq undef() ? "yes" : "no"' 

To będzie drukować "tak", choć wyraźnie pusty ciąg "" nie jest równa not defined. Korzystając z warnings, możemy złapać ten błąd.

Co chcesz, to prawdopodobnie coś jak:

for my $url (@sites) { 
    last unless defined $url; 
    ... 
} 

Albo, jeśli chcesz przejść do pewnego elementu tablicy:

my $start = 1; 
for my $index ($start .. $#sites) { 
    last unless defined $sites[$index]; 
    ... 
} 

samej zasadzie proste, ale stosując plaster tablicy i unikanie indeksów:

my $start = 1; 
for my $url (@sites[$start .. $#sites]) { 
    last unless defined $url; 
    ... 
} 

Należy pamiętać, że użycie last zamiast next jest logicznym odpowiednikiem warunku pętli while: Po napotkaniu niezdefiniowanej wartości pętla zostaje zakończona.

Więcej debugowanie: http://codepad.org/Nb5IwX0Q

Jeśli, podobnie jak w powyżej tej pasty, wydrukować licznik iteracji i wartości, będzie wyraźnie zobaczyć, kiedy pojawiają się różne ostrzeżenia. Otrzymujesz jedno ostrzeżenie dla pierwszego porównania "a" ne undef, jedno dla drugiego i dwa dla ostatniego. Ostatnie ostrzeżenia przychodzą, gdy $sitecount przekracza indeks maks. @sites, a porównujesz dwie niezdefiniowane wartości z ne.

+0

'()' ma wyższy priorytet niż 'ne' lub' = '. 'while (($ url = $ sites [$ sitecount]) ne undef) {...}' najwyraźniej ma drugi zbiór wokół $ url = $ sites [$ sitecount] ' –

+0

@BradGilbert Całkiem dobrze. Dzięki. Nie zauważyłem parens. – TLP

Powiązane problemy