Pergunta

Eu tenho uma variável perl $results que é retornado de um serviço.O valor deve ser uma matriz e $results deve ser uma referência de array.No entanto, quando a matriz contém apenas um item, $results será definido com esse valor, e não com uma matriz referenciada que contém esse item.

Eu quero fazer um foreach loop na matriz esperada.Sem verificar ref($results) eq 'ARRAY', existe alguma maneira de ter algo equivalente ao seguinte:

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

Esse exemplo de código específico funcionará para a referência, mas reclamará do escalar simples.

EDITAR:Devo esclarecer que não tenho como alterar o que é retornado do serviço.O problema é que o valor será escalar quando houver apenas um valor e será uma referência de array quando houver mais de um valor.

Foi útil?

Solução

não tenho certeza se há outra maneira senão:

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

Outras dicas

Outra solução seria agrupar a chamada para o servidor e fazer com que ele sempre retornasse um array para simplificar o resto da sua vida:

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

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

Então você sempre poderá saber que receberá de volta uma referência a um array, mesmo que seja apenas um item.

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

Bem, se você não pode fazer...

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

ou isto...

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

então você pode ter que tentar algo assustador e peludo como este!

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

e para evitar aquela avaliação de string perigosa, ela fica realmente feia e feia!!....

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

PS.Minha preferência seria abstraí-lo no exemplo sub ala call_to_service() dado por reatmon.

Eu refatoraria o código dentro do loop e então faria

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

É claro que eu só faria isso se o código no loop não fosse trivial.

Acabei de testar isso com:

#!/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 parece funcionar bem, então estou pensando que tem algo a ver com o resultado retornado do serviço?Se você não tem controle sobre o serviço de retorno, pode ser difícil decifrá-lo

Você pode fazer assim:

my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
  #do something
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top