¿Puedes forzar una referencia escalar o de matriz para que sea una matriz en Perl?

votos
25

Tengo una variable perl $resultsque se devuelve de un servicio. Se supone que el valor es una matriz y $resultsdebe ser una referencia de matriz. Sin embargo, cuando la matriz tiene solo un elemento, $resultsse establecerá en ese valor y no en una matriz referenciada que contenga ese elemento.

Quiero hacer un foreachciclo en la matriz esperada. Sin verificar ref($results) eq 'ARRAY', ¿hay alguna forma de tener algo equivalente a lo siguiente?

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

Esa muestra de código particular funcionará para la referencia, pero se quejará por el escalar simple.

EDITAR: Debería 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.

Publicado el 06/08/2008 a las 06:56
fuente por usuario
En otros idiomas...                            


6 respuestas

votos
26

No estoy seguro de que haya otra manera que no sea:

$result = [ $result ]   if ref($result) ne 'ARRAY';  
foreach .....
Respondida el 06/08/2008 a las 08:13
fuente por usuario

votos
12

Otra solución sería envolver la llamada al servidor y hacer que siempre devuelva 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 obtendrá una referencia a una matriz, incluso si se trata de un solo elemento.

foreach my $item (@{call_to_service()})
{
  ...
}
Respondida el 19/08/2008 a las 15:16
fuente por usuario

votos
2

Bueno, si no puedes hacer ...

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

o esto...

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

entonces quizás tengas que probar algo aterrador como este! ...

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

y para evitar esa evaluación de cadena peligrosa, se vuelve realmente feo !!

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

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

Respondida el 12/10/2008 a las 22:14
fuente por usuario

votos
0

Puede hacerlo de esta manera:

my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
  #do something
}
Respondida el 23/11/2016 a las 02:34
fuente por usuario

votos
0

Volvería a factorizar el código dentro del ciclo y luego haré

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

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

Respondida el 14/08/2008 a las 22:41
fuente por usuario

votos
0

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 funcionar bien, ¿entonces estoy pensando que tiene algo que ver con el resultado obtenido del servicio? Si no tiene control sobre el servicio de devolución, esto podría ser difícil de descifrar

Respondida el 06/08/2008 a las 07:22
fuente por usuario

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