#perl #arrays #reference #scalar
Вопрос:
У меня есть переменная perl $results
, которая возвращается из службы. Предполагается, что значение должно быть массивом и $results
должно быть ссылкой на массив. Однако, если в массиве есть только один элемент, ему $results
будет присвоено это значение, а не ссылочный массив, содержащий этот один элемент.
Я хочу сделать foreach
цикл для ожидаемого массива. Без проверки ref($results) eq 'ARRAY'
, есть ли какой-либо способ получить что-то эквивалентное следующему:
foreach my $result (@$results) {
# Process $result
}
Этот конкретный пример кода будет работать для справки, но будет жаловаться на простой скаляр.
ПРАВКА: Я должен уточнить, что у меня нет возможности изменить то, что возвращается из сервиса. Проблема в том, что значение будет скаляром, когда существует только одно значение, и оно будет ссылкой на массив, когда существует более одного значения.
Комментарии:
1. Такое поведение вызывает у меня желание закричать и сказать: «ГЛУПЫЙ ПЕРЛ!» Но потом я понимаю, что языки, которые не требуют этой ерунды, все еще делают это под капотом, что заставляет меня меньше беспокоиться….
Ответ №1:
я не уверен, что есть какой-то другой способ, кроме:
$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
}
и чтобы избежать этой опасной оценки строки, она становится действительно уродливой!!….
for my $result ( eval { $results->[0] } || $results, eval { @$results[1 .. $#{ $results }] } ) {
# Process result
}
PS. Я бы предпочел абстрагировать его в примере sub ala call_to_service (), приведенном reatmon.
Комментарии:
1. Это не оценка строки. И повторение цикла (некоторое выражение, включающее @$результаты) сильно отличается от повторения цикла (@$результаты). Первый будет копировать массив (потребляя память); второй будет использовать псевдоним для него (и позволит изменять элементы с помощью переменной цикла).
2. @ysth — Есть… см.раздел «Оценка результатов». Мое предложение состояло в том, чтобы использовать пример call_to_service (), приведенный ранее. Мой ответ был чем-то вроде «остроумного решения» для ограничения, наложенного плакатом, так что да, хорошо указать на его недостатки.
Ответ №4:
Я бы пересчитал код внутри цикла, а затем сделал
if( ref $results eq 'ARRAY' ){
my_sub($result) for my $result (@$results);
}else{
my_sub($results);
}
Конечно, я бы сделал это только в том случае, если бы код в цикле был нетривиальным.
Ответ №5:
Я только что проверил это с помощью:
#!/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." test1n"; } foreach my $r (@{testit()}){ print $r." test2n"; }
И, похоже, это работает нормально, поэтому я думаю, что это как-то связано с тем, что результат возвращается из службы?
Если у вас нет контроля над службой возврата, это может быть трудно взломать
Ответ №6:
Ты можешь сделать это вот так:
my @some_array
push (@some_array, results);
foreach my $elt(@some_array){
#do something
}
Комментарии:
1. Хотя этот фрагмент кода может решить вопрос, включая объяснение , действительно помогает улучшить качество вашего поста. Помните, что в будущем вы будете отвечать на этот вопрос для читателей, и эти люди могут не знать причин вашего предложения кода. Пожалуйста, также постарайтесь не загромождать свой код пояснительными комментариями, это снижает читабельность как кода, так и пояснений!