2008-08-06 35 views
24

Mam zmienną perl $results, która jest zwracana z usługi. Wartość ma być tablicą, a $results powinna być odwołaniem do tablicy. Jeśli jednak w tablicy znajduje się tylko jeden element, $results zostanie ustawiona na tę wartość, a nie tablica, do której odwołuje się ten jeden element.Czy możesz zmusić skalar lub tablicę, aby była tablicą w Perlu?

Chcę wykonać pętlę foreach dla oczekiwanej tablicy. Bez sprawdzania ref($results) eq 'ARRAY', czy jest jakiś sposób, aby mieć coś równoważna następującej:

foreach my $result (@$results) { 
    # Process $result 
} 

Że szczególności przykładowy kod będzie pracować dla odniesienia, ale skarżą się na prostym skalara.

EDYCJA: Należy wyjaśnić, że nie ma sposobu, aby zmienić to, co jest zwracane z usługi. Problem polega na tym, że wartość będzie skalarem, gdy istnieje tylko jedna wartość i będzie to odwołanie do tablicy, gdy istnieje więcej niż jedna wartość.

+0

Takie zachowanie sprawia, że ​​chcę krzyczeć i być jak "Stupid PERL!" Ale potem zdaję sobie sprawę, że języki, które nie wymagają tego nonsensu wciąż robią to pod maską, co sprawia, że ​​dręczy mnie nieco mniej ... – Rooster

Odpowiedz

26

nie jestem pewien, że istnieje inny sposób niż:

$result = [ $result ] if ref($result) ne 'ARRAY'; 
foreach ..... 
0

Właśnie przetestowane z:

#!/usr/bin/perl -w 
use strict; 

sub testit { 

my @ret =(); 
if (shift){ 
    push @ret,1; 
    push @ret,2; 
    push @ret,3; 
}else{ 
    push @ret,"oneonly"; 
} 

return \@ret; 
} 

foreach my $r (@{testit(1)}){ 
    print $r." test1\n"; 
} 
foreach my $r (@{testit()}){ 
    print $r." test2\n"; 
} 

I wydaje się działać ok, więc myślę, że to ma coś wspólnego z wynikiem coraz wrócił ze służby? Jeśli nie masz kontroli nad usługą powracającego to może być trudna do zgryzienia

0

bym ponownie czynnikiem kod wewnątrz pętla, a następnie wykonaj:

if(ref $results eq 'ARRAY'){ 
    my_sub($result) for my $result (@$results); 
}else{ 
    my_sub($results); 
} 

Oczywiście zrobiłbym to tylko wtedy, gdyby kod w pętli nie był trywialny.

12

Innym rozwiązaniem byłoby zawinąć połączenia z serwerem i mieć go zawsze zwraca tablicę do uproszczenia resztę swojego życia:

sub call_to_service 
{ 
    my $returnValue = service::call(); 

    if (ref($returnValue) eq "ARRAY") 
    { 
     return($returnValue); 
    } 
    else 
    { 
     return([$returnValue]); 
    } 
} 

Następnie można zawsze wiedzieć, że dostaniesz z powrotem odniesienie do tablicę, nawet jeśli był to tylko jeden przedmiot.

foreach my $item (@{call_to_service()}) 
{ 
    ... 
} 
2

Cóż, jeśli nie można zrobić ...

for my $result (ref $results eq 'ARRAY' ? @$results : $results) { 
    # Process result 
} 

czy to ...

for my $result (! ref $results ? $results : @$results) { 
    # Process result 
} 

to może trzeba spróbować czegoś owłosioną straszny jak ten! .. ..

for my $result (eval { @$results }, eval $results) { 
    # Process result 
} 

i aby uniknąć niebezpiecznego ciągu sznurków, staje się naprawdę brzydko fugly !! ...

for my $result (eval { $results->[0] } || $results, eval { @$results[1 .. $#{ $results }] }) { 
    # Process result 
} 

PS. Moją preferencją byłoby wyodrębnienie go w podrzędnym przykładzie call_to_service() podanym przez reatmon.

+0

To nie jest ciąg eval. Pętla (niektóre wyrażenia zawierające wyniki @ $) bardzo się różnią od zapętleń (wyniki @ $). Pierwsza z nich skopiuje tablicę (zużywa pamięć); ten drugi będzie nazywał go (i pozwala na modyfikowanie elementów za pomocą zmiennej pętli). – ysth

+0

@ysth - Istnieje ... zobacz "wyniki eval $". Moja sugestia dotyczyła wcześniej podanego przykładu call_to_service(). Moja odpowiedź brzmiała trochę "język w policzkach" w odniesieniu do ograniczenia narzuconego przez plakat, tak więc dobrze jest wskazać jego wady. – draegtun

0

Można to zrobić tak:

my @some_array 
push (@some_array, results); 
foreach my $elt(@some_array){ 
    #do something 
} 
+0

Chociaż ten fragment kodu może rozwiązać pytanie, [w tym wyjaśnienie] (// meta.stackexchange.com/questions/114762/explaining-entirely-code-ans -answers) naprawdę pomaga poprawić jakość twojego posta. Pamiętaj, że odpowiadasz na pytanie przeznaczone dla czytelników w przyszłości, a te osoby mogą nie znać powodów sugestii dotyczących kodu. Proszę również starać się nie tłumić kodu za pomocą komentarzy wyjaśniających, co zmniejsza czytelność zarówno kodu, jak i objaśnień! – kayess