Являются ли ссылки лучшими возвращаемыми значениями в Perl-функциях?
Каковы плюсы и минусы возврата массива или хэша по сравнению с возвратом ссылки на него?
Есть ли влияние на память или время выполнения?
Каковы функциональные различия между этими двумя?
sub i_return_an_array
{
my @a = ();
# push things in @a;
return @a;
}
sub i_return_a_ref
{
my @a = ();
# push things in @a;
return \@a;
}
my @v = i_return_an_array();
my $v = i_return_a_ref();
Ответы
Ответ 1
Да, есть влияние на память и время выполнения - возврат ссылки возвращает один (относительно небольшой) скаляр и ничего больше. Возвращение массива или хеша в виде списка делает мелкую копию массива/хеша и возвращает это, что может занять значительное время, чтобы сделать копию и память для хранения копии, если массив/хэш большой.
Функциональное различие между ними - это просто вопрос о том, работаете ли вы с результатом в виде массива/хэша или как arrayref/hashref. Некоторые люди считают, что ссылки гораздо труднее работать; лично я не считаю это существенной разницей.
Другим функциональным отличием является то, что вы не можете возвращать несколько массивов или хешей в виде списков (они сглаживаются в один список), но вы можете возвращать несколько ссылок. Когда это происходит, это детали убийцы, которые заставляют вас использовать ссылки, но мой опыт в том, что он возникает очень редко, поэтому я не знаю, насколько важно, чтобы он считался общим.
Переходя к заголовку вопроса, я считаю, что самый важный фактор, связанный с возвратом списков против ссылок, заключается в том, что вы должны быть последовательными, чтобы не тратить время на запоминание, какие функции возвращают массивы/хэши и которые возвращают ссылки, Учитывая, что ссылки в некоторых ситуациях лучше, и, по крайней мере, для меня ссылки никогда не будут значительно хуже, я предпочитаю стандартизировать всегда возвращаемые массивы/хэши как ссылки, а не как списки.
(Вы также можете выбрать стандартизацию при использовании wantarray
в своих подписях, чтобы они возвращали списки в контексте списка и ссылки в скалярном контексте, но я склонен считать это в значительной степени бессмысленным чрезмерным усложнением.)
Ответ 2
Влияние производительности заметно, когда массив становится больше, но только около 50% на perl 5.10.
Я обычно предпочитаю возвращать ссылку, так как код легче читать: функция имеет только один возврат значение и позволяет избежать некоторых ошибок (автоматическая скалярная оценка) в качестве ссылки, указанной в manu_v.
#! /usr/bin/perl
use Benchmark;
sub i_return_an_array
{
my @a = (1 .. shift);
# push things in @a;
return @a;
}
sub i_return_a_ref
{
my @a = (1 .. shift);
# push things in @a;
return \@a;
}
for my $nb (1, 10, 100, 1000, 10000) {
Benchmark::cmpthese(0, {
"array_$nb" => sub { my @v = i_return_an_array($nb); },
"ref_$nb" => sub { my $v = i_return_a_ref($nb); },
});
}
возвращает:
Rate ref_1 array_1
ref_1 702345/s -- -3%
array_1 722083/s 3% --
Rate array_10 ref_10
array_10 230397/s -- -29%
ref_10 324620/s 41% --
Rate array_100 ref_100
array_100 27574/s -- -47%
ref_100 52130/s 89% --
Rate array_1000 ref_1000
array_1000 2891/s -- -51%
ref_1000 5855/s 103% --
Rate array_10000 ref_10000
array_10000 299/s -- -48%
ref_10000 578/s 93% --
В других версиях perl цифры могут быть разными.
Ответ 3
Что касается интерфейса, то возврат массива позволяет вам легче обрабатывать такие вещи, как map и grep, не прибегая к @{bletchorousness}
.
Но с хешами часто бывает полезно возвращать ссылку, потому что тогда вы можете делать умные вещи, такие как my $val = function->{key}
, не присваивая промежуточной переменной.
Ответ 4
Короткий ответ: это зависит от размера того, что вы возвращаете. Если он мал, вы можете вернуть весь массив.
Подробнее см. в разделе Вопрос Возвращает весь массив из подпрограммы Perl неэффективно?.
Ответ 5
Обратите внимание, что на самом деле невозможно вернуть массив или хэш из функции. Единственное, что может вернуть функция, это список скаляров. Когда вы говорите return @a
, вы возвращаете содержимое массива.
В некоторых программах он работает более чисто, чтобы вернуть содержимое массива. В некоторых программах он работает более чисто, чтобы возвращать ссылку на массив. Сделайте свое решение в каждом конкретном случае.