Подтвердить что ты не робот

Можете ли вы заставить скаляр или массив ref быть массивом в Perl?

У меня есть переменная perl $results, которая возвращается из службы. Значение должно быть массивом, а $results должно быть ссылкой на массив. Однако, когда массив имеет только один элемент в нем, $results будет установлен на это значение, а не массив ссылок, содержащий этот один элемент.

Я хочу сделать цикл foreach в ожидаемом массиве. Не проверяя ref($results) eq 'ARRAY', есть ли способ иметь что-то эквивалентное следующему:

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

Этот пример кода будет работать для ссылки, но будет жаловаться на простой скаляр.

EDIT: я должен уточнить, что мне не удается изменить то, что возвращается из службы. Проблема заключается в том, что значение будет скаляром, когда есть только одно значение, и оно будет ссылкой на массив, когда имеется более одного значения.

4b9b3361

Ответ 1

im не уверен, есть ли другой способ, чем:

$result = [ $result ]   if ref($result) ne 'ARRAY';  
foreach .....

Ответ 2

Другим решением было бы обернуть вызов на сервер и всегда возвращать массив, чтобы упростить всю оставшуюся жизнь:

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

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

Тогда вы всегда можете узнать, что вы вернете ссылку на массив, даже если это был только один элемент.

foreach my $item (@{call_to_service()})
{
  ...
}

Ответ 3

Хорошо, если вы не можете сделать...

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.

Ответ 4

Я только что проверил это с помощью

#!/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";
}

И, похоже, все работает нормально, поэтому я думаю, что это связано с тем, что результат возвращается из службы? Если у вас нет контроля над возвращающейся услугой, это может быть трудно взломать

Ответ 5

Я бы повторно определил код внутри цикла, а затем сделаю

if( ref $results eq 'ARRAY' ){
    my_sub($result) for my $result (@$results);
}else{
    my_sub($results);
}

Конечно, я бы сделал это только в том случае, если код в цикле был нетривиальным.

Ответ 6

Вы можете сделать это следующим образом:

my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
  #do something
}