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

голоса
25

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

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

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

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

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

Задан 06/08/2008 в 06:56
источник пользователем
На других языках...                            


6 ответов

голоса
26

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

$result = [ $result ]   if ref($result) ne 'ARRAY';  
foreach .....
Ответил 06/08/2008 d 08:13
источник пользователем

голоса
12

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

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

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

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

foreach my $item (@{call_to_service()})
{
  ...
}
Ответил 19/08/2008 d 15:16
источник пользователем

голоса
2

Ну, если вы не можете сделать ...

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. Мое предпочтение было бы абстрагировать прочь в суб ала call_to_service () пример, приведенный reatmon.

Ответил 12/10/2008 d 22:14
источник пользователем

голоса
0

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

my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
  #do something
}
Ответил 23/11/2016 d 05:34
источник пользователем

голоса
0

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

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

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

Ответил 14/08/2008 d 22:41
источник пользователем

голоса
0

Я только что проверил это с:

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

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

Ответил 06/08/2008 d 07:22
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more