2008-08-06 14 views
24

Ho una variabile perl $results che viene restituita da un servizio. Il valore dovrebbe essere un array e $results dovrebbe essere un riferimento di matrice. Tuttavia, quando l'array contiene solo un elemento, $results verrà impostato su tale valore e non su un array referenziato che contiene quell'elemento.Potete forzare uno scalar o un array ref ad essere una matrice in Perl?

Voglio fare un ciclo foreach sulla matrice prevista. Senza controllare ref($results) eq 'ARRAY', c'è qualche modo per avere qualcosa di equivalente a quanto segue:

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

Questo esempio di codice particolare lavorerà per il riferimento, ma si lamenterà per la semplice scalare.

EDIT: Vorrei chiarire che non c'è modo per me di cambiare ciò che viene restituito dal servizio. Il problema è che il valore sarà uno scalare quando c'è un solo valore e sarà un riferimento di matrice quando c'è più di un valore.

+0

Questo comportamento mi fa venire voglia di urlare e di essere come "PERL STUPIDO!" Ma poi mi rendo conto che le lingue che non richiedono questa assurdità lo fanno ancora sotto il cofano, il che mi dà fastidio in meno ... – Rooster

risposta

26

im non sicuro che ci sia altro modo che:

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

Ho appena testato questo con:

#!/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"; 
} 

e sembra funzionare bene, così sto pensando che abbia qualcosa a che fare con il risultato sempre tornato dal servizio? Se si dispone di alcun controllo sul servizio di restituire questo potrebbe essere difficile quello di rompere

0

vorrei ri-factor il codice all'interno del loop e poi fare

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

Naturalmente mi farlo solo se il codice nel ciclo era non banale.

12

Un'altra soluzione potrebbe essere quella di avvolgere la chiamata al server e lo hanno restituire sempre un array per semplificare il resto della tua vita:

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

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

Poi sempre si può sapere che si otterrà di nuovo un riferimento alla un array, anche se era solo un oggetto.

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

Beh, se non si può fare ...

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

o questo ...

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

allora si potrebbe avere di provare qualcosa di peloso spaventoso come questo! .. ..

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

e per evitare che stringa pericolosa eval diventi veramente brutto fugace !! ....

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

PS. La mia preferenza sarebbe quella di estrapolarlo in subla call_to_service() esempio dato da reatmon.

+0

Questa non è una stringa di valutazione. E il looping (alcune espressioni che coinvolgono i risultati @ $) è molto diverso dal looping (@ $ results). Il primo copia l'array (che consuma memoria); quest'ultimo lo alias (e consente di modificare gli elementi tramite la variabile loop). – ysth

+0

@ysth - C'è ... vedi "eval $ results". Il mio suggerimento era di usare l'esempio call_to_service() dato in precedenza. La mia risposta è stata un po 'di "lingua in soluzione guancia" per la restrizione imposta dal poster quindi sì è bene sottolineare i suoi difetti. – draegtun

0

Si può fare in questo modo:

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

Anche se questo snippet di codice può risolvere la domanda, [compresa una spiegazione] (// meta.stackexchange.com/questions/114762/explaining-entally-code-based-answers) aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro, e queste persone potrebbero non conoscere le ragioni del tuo suggerimento sul codice. Cerca anche di non affollare il tuo codice con commenti esplicativi, questo riduce la leggibilità sia del codice che delle spiegazioni! – kayess