2008-08-06 12 views
24

Tengo una variable perl $results que se devuelve de un servicio. Se supone que el valor es una matriz, y $results debe ser una referencia de matriz. Sin embargo, cuando la matriz tiene solo un elemento, $results se establecerá en ese valor y no en una matriz referenciada que contenga ese elemento.¿Se puede forzar una referencia escalar o de matriz para que sea una matriz en Perl?

Quiero hacer un bucle foreach en la matriz esperada. Sin comprobar ref($results) eq 'ARRAY', ¿hay alguna manera de tener algo equivalente a lo siguiente:

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

Eso particular, ejemplo de código funcionará para la referencia, pero se quejará por la simple escalar.

EDIT: Debo aclarar que no hay forma de que cambie lo que devuelve el servicio. El problema es que el valor será escalar cuando solo hay un valor y será una referencia de matriz cuando haya más de un valor.

+0

Este comportamiento hace que quiere gritar y ser como, "Perl ESTÚPIDO!" Pero luego me doy cuenta de que los lenguajes que no requieren esta tontería todavía lo hacen bajo el capó, lo que hace que me moleste un poco menos ... – Rooster

Respuesta

26

no estoy seguro de que hay otra manera que:

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

he acabo de probar esto 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"; 
} 

Y parece que funciona bien, así que estoy pensando que tiene algo que ver con el resultado siendo devuelta del servicio? Si no tiene ningún control sobre el servicio de devolver este podría ser difícil uno a agrietarse

0

Me re-factor de código dentro de la bucle y luego hacer

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

Por supuesto que solo haría eso si el código en el bucle no fuera trivial.

12

Otra solución sería la de envolver la llamada al servidor y tenerlo siempre devolver una matriz para simplificar el resto de su vida:

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

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

Entonces siempre se puede saber que va a volver una referencia a una matriz, incluso si era solo un elemento.

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

Bueno, si no se puede hacer ...

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

o esto ...

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

entonces es posible que tenga que probar algo peluda miedo como esta! .. ..

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

y para evitar esa cadena peligrosa eval se vuelve realmente feo fugly! ....

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

PS. Mi preferencia sería abstraerlo en el ejemplo de sub ala call_to_service() dado por reatmon.

+0

Eso no es una evaluación de cadena. Y el bucle (una expresión que involucra @ $ resultados) es muy diferente de un bucle (@ $ resultados). El primero copiará la matriz (memoria consumida); este último lo aliará (y permitirá modificar elementos a través de la variable de bucle). – ysth

+0

@ysth - Hay ... ver "eval $ results". Mi sugerencia fue utilizar el ejemplo de call_to_service() dado anteriormente. Mi respuesta fue un poco de "solución irónica" a la restricción impuesta por el póster, así que sí, es bueno señalar sus defectos. – draegtun

0

Puede hacerlo de esta manera:

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

Si bien este fragmento de código puede resolver la pregunta, [incluyendo una explicación] (// meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) realmente ayuda a mejorar la calidad de su publicación. Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. Por favor, intente no saturar su código con comentarios explicativos, ¡esto reduce la legibilidad tanto del código como de las explicaciones! – kayess

Cuestiones relacionadas