Pouvez-vous forcer une référence scalaire ou de tableau à être un tableau en Perl ?
Question
J'ai une variable Perl $results
qui est renvoyé par un service.La valeur est censée être un tableau, et $results
devrait être une référence de tableau.Cependant, lorsque le tableau ne contient qu'un seul élément, $results
sera défini sur cette valeur, et non sur un tableau référencé contenant cet élément.
je veux faire un foreach
boucle sur le tableau attendu.Sans vérifier ref($results) eq 'ARRAY'
, existe-t-il un moyen d'avoir quelque chose d'équivalent à ce qui suit :
foreach my $result (@$results) {
# Process $result
}
Cet exemple de code particulier fonctionnera pour la référence, mais se plaindra du simple scalaire.
MODIFIER:Je dois préciser qu'il n'y a aucun moyen pour moi de modifier ce qui est renvoyé par le service.Le problème est que la valeur sera un scalaire lorsqu’il n’y a qu’une seule valeur et ce sera une référence de tableau lorsqu’il y a plus d’une valeur.
La solution
je ne suis pas sûr qu'il existe un autre moyen que :
$result = [ $result ] if ref($result) ne 'ARRAY'; foreach .....
Autres conseils
Une autre solution serait d'encapsuler l'appel au serveur et de lui faire toujours renvoyer un tableau pour simplifier le reste de votre vie :
sub call_to_service
{
my $returnValue = service::call();
if (ref($returnValue) eq "ARRAY")
{
return($returnValue);
}
else
{
return( [$returnValue] );
}
}
Vous pouvez alors toujours savoir que vous obtiendrez une référence à un tableau, même s’il ne s’agissait que d’un seul élément.
foreach my $item (@{call_to_service()})
{
...
}
Eh bien, si vous ne pouvez pas le faire...
for my $result ( ref $results eq 'ARRAY' ? @$results : $results ) {
# Process result
}
ou ca...
for my $result ( ! ref $results ? $results : @$results ) {
# Process result
}
alors vous devrez peut-être essayer quelque chose de poilu et effrayant comme celui-ci !....
for my $result ( eval { @$results }, eval $results ) {
# Process result
}
et pour éviter cette dangereuse évaluation de chaîne, cela devient vraiment moche !!....
for my $result ( eval { $results->[0] } || $results, eval { @$results[1 .. $#{ $results }] } ) {
# Process result
}
PS.Ma préférence serait de l'abstraire dans l'exemple sub ala call_to_service() donné par reatmon.
Je refactoriserais le code à l'intérieur de la boucle, puis je ferais
if( ref $results eq 'ARRAY' ){
my_sub($result) for my $result (@$results);
}else{
my_sub($results);
}
Bien sûr, je ne le ferais que si le code de la boucle n’était pas trivial.
Je viens de tester ça avec :
#!/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"; }
Et cela semble fonctionner correctement, donc je pense que cela a quelque chose à voir avec le résultat renvoyé par le service ?Si vous n'avez aucun contrôle sur le service de retour, cela pourrait être difficile à résoudre
Vous pouvez procéder ainsi :
my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
#do something
}