Ответ 1
im не уверен, есть ли другой способ, чем:
$result = [ $result ] if ref($result) ne 'ARRAY'; foreach .....
У меня есть переменная perl $results
, которая возвращается из службы. Значение должно быть массивом, а $results
должно быть ссылкой на массив. Однако, когда массив имеет только один элемент в нем, $results
будет установлен на это значение, а не массив ссылок, содержащий этот один элемент.
Я хочу сделать цикл foreach
в ожидаемом массиве. Не проверяя ref($results) eq 'ARRAY'
, есть ли способ иметь что-то эквивалентное следующему:
foreach my $result (@$results) {
# Process $result
}
Этот пример кода будет работать для ссылки, но будет жаловаться на простой скаляр.
EDIT: я должен уточнить, что мне не удается изменить то, что возвращается из службы. Проблема заключается в том, что значение будет скаляром, когда есть только одно значение, и оно будет ссылкой на массив, когда имеется более одного значения.
im не уверен, есть ли другой способ, чем:
$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] );
}
}
Тогда вы всегда можете узнать, что вы вернете ссылку на массив, даже если это был только один элемент.
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
}
и чтобы избежать опасной строки eval, она становится действительно уродливой, fugly!!....
for my $result ( eval { $results->[0] } || $results, eval { @$results[1 .. $#{ $results }] } ) {
# Process result
}
PS. Мое предпочтение было бы отвлечь его в примере sub ala call_to_service(), заданном reatmon.
Я только что проверил это с помощью
#!/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"; }
И, похоже, все работает нормально, поэтому я думаю, что это связано с тем, что результат возвращается из службы? Если у вас нет контроля над возвращающейся услугой, это может быть трудно взломать
Я бы повторно определил код внутри цикла, а затем сделаю
if( ref $results eq 'ARRAY' ){
my_sub($result) for my $result (@$results);
}else{
my_sub($results);
}
Конечно, я бы сделал это только в том случае, если код в цикле был нетривиальным.
Вы можете сделать это следующим образом:
my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
#do something
}