você pode forçar qualquer um escalar ou matriz ref ser uma matriz em Perl?

votos
25

Eu tenho uma variável perl $resultsque é retornado de um serviço. O valor é suposto ser uma matriz, e $resultsdeve ser uma matriz de referência. No entanto, quando a matriz tem apenas um item na mesma, $resultsserá definido para esse valor, e não uma matriz de referência que contém aquele item.

Eu quero fazer um foreachlaço na série esperada. Sem verificação ref($results) eq 'ARRAY', existe alguma maneira de ter algo equivalente ao seguinte:

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

Essa amostra de código especial vai trabalhar para a referência, mas vai reclamar para o escalar simples.

EDIT: Devo esclarecer que não há nenhuma maneira para eu mudar o que é retornado do serviço. O problema é que o valor será um escalar quando existe apenas um único valor e será uma referência de matriz quando há mais do que um valor.

Publicado 06/08/2008 em 06:56
fonte usuário
Em outras línguas...                            


6 respostas

votos
26

eu não tenho certeza há alguma outra forma que:

$result = [ $result ]   if ref($result) ne 'ARRAY';  
foreach .....
Respondeu 06/08/2008 em 08:13
fonte usuário

votos
12

Outra solução seria para embrulhar a chamada para o servidor e tê-lo sempre retornar uma matriz para simplificar o resto de sua vida:

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

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

Então você pode sempre saber que você vai receber de volta uma referência a uma matriz, mesmo que fosse apenas um item.

foreach my $item (@{call_to_service()})
{
  ...
}
Respondeu 19/08/2008 em 15:16
fonte usuário

votos
2

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 peludo assustador assim! ....

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

e para evitar essa seqüência perigosa eval torna-se realmente feio fugly !! ....

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

PS. Minha preferência seria para abstrair-lo afastado em sub ala call_to_service exemplo () dada pela reatmon.

Respondeu 12/10/2008 em 22:14
fonte usuário

votos
0

Você pode fazê-lo como este:

my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
  #do something
}
Respondeu 23/11/2016 em 05:34
fonte usuário

votos
0

Eu re-fator o código dentro do loop e, em seguida, fazer

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 foi não-trivial.

Respondeu 14/08/2008 em 22:41
fonte usuário

votos
0

Eu apenas testei 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 ok, então eu estou pensando que tem algo a ver com o resultado sendo retornados do serviço? Se você não tem controle sobre o serviço de devolver este pode ser difícil um de crack

Respondeu 06/08/2008 em 07:22
fonte usuário

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