Являются ли ссылки лучшими возвращаемыми значениями в 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}, не присваивая промежуточной переменной.

Ответ 5

Обратите внимание, что на самом деле невозможно вернуть массив или хэш из функции. Единственное, что может вернуть функция, это список скаляров. Когда вы говорите return @a, вы возвращаете содержимое массива.

В некоторых программах он работает более чисто, чтобы вернуть содержимое массива. В некоторых программах он работает более чисто, чтобы возвращать ссылку на массив. Сделайте свое решение в каждом конкретном случае.