Można wymusić albo skalar lub array ref być tablicą w Perl?

głosy
25

Mam zmiennej perl $results, który pobiera zwrócony z usługi. Wartość ma być tablicą, a $resultspowinno być odniesienie tablicą. Jednak, gdy tablica ma tylko jeden element w nim, $resultszostanie ustawiony na tę wartość, a nie odwołuje się tablicę zawierającą że jeden element.

Chcę zrobić foreachpętlę na oczekiwanym tablicy. Bez sprawdzenia ref($results) eq 'ARRAY', czy jest jakiś sposób, aby mieć coś równoważne do następujących:

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

Zwłaszcza że przykładowy kod będzie pracować dla odniesienia, ale skarżą się na prostym skalara.

EDIT: należy wyjaśnić, że nie ma dla mnie sposób, aby zmienić to, co jest zwracany z usługi. Problem polega na tym, że wartość będzie skalar, gdy istnieje tylko jedna wartość i będzie odwołanie do tablicy, gdy istnieje więcej niż jedna wartość.

Utwórz 06/08/2008 o 06:56
źródło użytkownik
W innych językach...                            


6 odpowiedzi

głosy
0

Właśnie to 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

Odpowiedział 06/08/2008 o 07:22
źródło użytkownik

głosy
26

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

$result = [ $result ]   if ref($result) ne 'ARRAY';  
foreach .....
Odpowiedział 06/08/2008 o 08:13
źródło użytkownik

głosy
0

Chciałbym ponownie czynnikiem kod wewnątrz pętli, a następnie wykonaj

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

Oczywiście chciałbym zrobić tylko, że jeśli kod w pętli było nietrywialne.

Odpowiedział 14/08/2008 o 22:41
źródło użytkownik

głosy
12

Innym rozwiązaniem byłoby zawinąć połączenia z serwerem i mieć go zawsze zwraca tablicę w celu 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 odwołanie do tablicy, nawet jeśli był to tylko jeden element.

foreach my $item (@{call_to_service()})
{
  ...
}
Odpowiedział 19/08/2008 o 15:16
źródło użytkownik

głosy
2

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

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

albo 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ąć tego niebezpiecznego ciąg eval staje się naprawdę brzydki fugly !! ....

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

PS. Moje preferencje byłoby abstrakcyjne go daleko w sub ala call_to_service () Przykład podany przez reatmon.

Odpowiedział 12/10/2008 o 22:14
źródło użytkownik

głosy
0

Można to zrobić tak:

my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
  #do something
}
Odpowiedział 23/11/2016 o 05:34
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more