¿Puede forzar un escalar o array ref a ser un array en Perl?


Tengo una variable perl $results que se devuelve de un servicio. El valor se supone que es una matriz, y $results debe ser una referencia de matriz. Sin embargo, cuando la matriz tiene solo un elemento en ella, $results se establecerá a ese valor, y no a una matriz referenciada que contenga ese elemento.

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

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

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

EDITAR: Debo aclarar que no hay manera para mí de cambiar lo que se devuelve del servicio. El problema es que el valor será un escalar cuando solo hay un valor y será una referencia de matriz cuando hay más de un valor.

Author: Community, 2008-08-06

6 answers

No estoy seguro de que haya otra manera que:

$result = [ $result ]   if ref($result) ne 'ARRAY';  
foreach .....
 26
Author: svrist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-06 07:13:16

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 puede saber que obtendrá una referencia a un array, incluso si era solo un elemento.

foreach my $item (@{call_to_service()})
{
  ...
}
 12
Author: user1917,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 14:16:57

Bueno, si no puedes hacerlo...

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 peludo de miedo como este!....

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

¡Y para evitar esa peligrosa evaluación de cuerdas se vuelve realmente fea y fugaz!!....

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

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

 2
Author: draegtun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-21 15:03:26

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

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 bucle no fuera trivial.

 0
Author: Brad Gilbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-14 21:45:53

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 que se devuelve del servicio? Si no tiene control sobre el servicio de devolución, esto podría ser difícil de descifrar

 0
Author: svrist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-12 12:29:45

Puedes hacerlo así:

my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
  #do something
}
 0
Author: kayess,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-10 09:37:20