Perl でスカラー参照または配列参照を強制的に配列にすることはできますか?
質問
Perl変数があります $results
サービスから返されるもの。値は配列であると想定されており、 $results
配列参照である必要があります。ただし、配列に項目が 1 つしかない場合は、 $results
は、その 1 つの項目を含む参照配列ではなく、その値に設定されます。
やりたいのですが foreach
期待される配列をループします。確認せずに ref($results) eq 'ARRAY'
, 、次と同等のものを得る方法はありますか:
foreach my $result (@$results) {
# Process $result
}
この特定のコード サンプルはリファレンスとしては機能しますが、単純なスカラーでは問題が発生します。
編集:サービスから返される内容を変更する方法はないことを明確にしておきます。問題は、値が 1 つしかない場合は値がスカラーになり、値が複数ある場合は配列参照になることです。
解決
次の方法以外に方法があるかわかりません。
$result = [ $result ] if ref($result) ne 'ARRAY'; foreach .....
他のヒント
別の解決策は、サーバーへの呼び出しをラップし、サーバーが常に配列を返すようにして、残りの作業を簡素化することです。
sub call_to_service
{
my $returnValue = service::call();
if (ref($returnValue) eq "ARRAY")
{
return($returnValue);
}
else
{
return( [$returnValue] );
}
}
そうすれば、それが 1 つの項目だけであっても、配列への参照が返されることが常にわかります。
foreach my $item (@{call_to_service()})
{
...
}
まあ、それができないなら…
for my $result ( ref $results eq 'ARRAY' ? @$results : $results ) {
# Process result
}
それともこれ...
for my $result ( ! ref $results ? $results : @$results ) {
# Process result
}
それなら、このような毛むくじゃらの恐ろしいことを試してみる必要があるかもしれません!....
for my $result ( eval { @$results }, eval $results ) {
# Process result
}
そしてその危険な文字列の評価を避けるために、それは本当に醜い、醜いものになります!!....
for my $result ( eval { $results->[0] } || $results, eval { @$results[1 .. $#{ $results }] } ) {
# Process result
}
PS.私の好みは、reatmon が提供する call_to_service() のサブアラの例でそれを抽象化することです。
ループ内のコードをリファクタリングしてから実行します
if( ref $results eq 'ARRAY' ){
my_sub($result) for my $result (@$results);
}else{
my_sub($results);
}
もちろん、ループ内のコードが重要な場合にのみこれを行います。
これを次のようにテストしました。
#!/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"; }
それは問題なく動作しているようですので、サービスから返される結果に関係があると思いますか?返品サービスを制御できない場合、これを突破するのは難しいかもしれません
次のようにして実行できます。
my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
#do something
}