Você pode forçar um escalar ou uma referência de array a ser um array em Perl?
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.
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
}