Почему я возвратил бы хеш или ссылку хеша в Perl?

Каков самый эффективный способ выполнить ниже? (Я знаю, что они выполняют то же самое, но как большинство людей сделало бы это между этими тремя, и почему?)

Файл a.pl

my %hash = build_hash();
# Do stuff with hash using $hash{$key}
sub build_hash
{
    # Build some hash
    my %hash = ();
    my @k = qw(hi bi no th xc ul 8e r);
    for ( @k )
    {
        $hash{$k} = 1;
    }

    # Does this return a copy of the hash??
    return %hash;
}

Файл b.pl

my $hashref = build_hash();
# Do stuff with hash using $hashref->{$key}
sub build_hash
{
    # Build some hash
    my %hash = ();
    my @k = qw(hi bi no th xc ul 8e r);
    for ( @k )
    {
        $hash{$k} = 1;
    }

    # Just return a reference (smaller than making a copy?)
    return \%hash;
}

Файл c.pl

my %hash = %{build_hash()};
# Do stuff with hash using $hash{$key}
# It is better, because now we don't have to dereference our hashref each time using ->?

sub build_hash
{
    # Build some hash
    my %hash = ();
    my @k = qw(hi bi no th xc ul 8e r);
    for ( @k )
    {
        $hash{$k} = 1;
    }

    return \%hash;
}
10
задан Peter Mortensen 8 January 2014 в 12:30
поделиться

8 ответов

Я предпочитаю вернуть хэш-файл по двум причинам. Первая - он использует немного меньше памяти, так как нет копии. Вторая, она позволяет делать это, если вам нужен только один кусочек хэша.

my $value = build_hash()->{$key};

Научитесь любить хэш-ссылки, вы будете часто их видеть, как только начнете использовать объекты.

22
ответ дан 3 December 2019 в 13:23
поделиться

a. pl и c.pl требуют, чтобы была взята копия хэша (а внутренний хэш функции помечен как свободная память). С другой стороны, b.pl строит хэш всего один раз и требует немного дополнительной памяти для возврата ссылки, по которой вы можете работать. Таким образом, b.pl, скорее всего, является наиболее эффективной формой тройки, как в пространстве, так и во времени.

.
2
ответ дан 3 December 2019 в 13:23
поделиться

Я собираюсь пойти против зерна и того, что говорят все остальные, и сказать, что я предпочитаю, чтобы мои данные возвращались в виде гашиша (ну, в виде чётного списка, который, скорее всего, будет интерпретирован как гашиш). Я работаю в среде, где мы обычно делаем такие вещи, как следующий фрагмент кода, и гораздо проще комбинировать и сортировать, а также нарезать кубики и кубики, когда не нужно разыменовывать каждую другую строку. (Также приятно знать, что кто-то не может повредить ваш хэш-файл, потому что вы передали все по значению. edit: unless you've got references to other objects/hashes/arrays in the hash-values, then you're in trouble anyway).

my %filtered_config_slice = 
   hashgrep { $a !~ /^apparent_/ && defined $b } (
   map { $_->build_config_slice(%some_params, some_other => 'param') } 
   ($self->partial_config_strategies, $other_config_strategy)
);

This approximates something that my code might do: building a configuration for a object based on various configuration strategy objects (some of which the object knows about inherently, plus some extra guy) and then filters out some из них as irrelevant.

(Да, у нас есть хорошие инструменты вроде hashgrep и hashmap и lkeys, которые делают полезные вещи с хэшами. $a и $b устанавливаются на клавишу и значение каждого элемента списка соответственно). (Да, у нас есть люди, которые могут программировать на этом уровне. Найм - это неприятно, но у нас есть качественный продукт.)

Если вы не собираетесь делать ничего подобного, похожего на функциональное программирование, или если вам нужно больше производительности (вы профилировали?), то конечно, используйте хэши.

(Да, у нас есть люди, которые могут программировать на этом уровне.
2
ответ дан 3 December 2019 в 13:23
поделиться

Относительно возвращения гашиша из функционировать, как правило, вы должны вернуться сам гашиш, а не ссылка. Вы может быть использована ссылка, если хэш Огромный, и память или время - это проблема, но это не должно быть твоим первым беспокойством. -- ...заставить код работать.

Мне придется не согласиться с Эфиром. Было время, когда я занимал эту позицию, но быстро оказался в аду, когда должен был вспомнить, какие subs возвращали хэши и какие возвращали хэши, что было довольно серьёзным препятствием для простого заставления кода работать. Важно стандартизировать либо всегда возвращающий хэш/массив, либо всегда возвращающий хэш/массив, если только вы не хотите постоянно спотыкаться о себя.

Что касается стандартизации, то я вижу несколько преимуществ использования ссылок:

  • Когда вы возвращаете хэш или массив, то на самом деле вы возвращаете список, содержащий сплющенную копию оригинального хэша/массива. Так же как и передача параметров хэша/массива в sub, это имеет недостаток, заключающийся в том, что вы можете посылать только один список за раз. Конечно, не часто нужно возвращать несколько списков значений, но это случается, так зачем же выбирать стандартизацию, которая исключает это?

  • Преимущества (обычно пренебрежимо малы) производительности/памяти при возврате одного скаляра, а не потенциально гораздо большего куска данных.

  • Она поддерживает согласованность с кодом OO, который часто передает объекты (т.е. благословенные ссылки) туда и обратно.

  • Если по какой-либо причине важно, чтобы у вас была свежая копия хэша/массива, а не ссылка на оригинал, код вызова может легко сделать такую копию, как показано в c.pl . Однако, если вы вернете копию хэша, то вызывающий абонент не сможет превратить ее в ссылку на оригинал. (В случаях, когда это выгодно, функция может сделать копию и вернуть ссылку на копию, таким образом защищая оригинал и в то же время избегая "this возвращает хэши, , который возвращает хэши", ад, о котором я упоминал ранее)

  • Как упоминал Шверн, очень приятно иметь возможность сделать мой $foo = $obj->some_data->{key}.

Единственное преимущество, которое я могу видеть в всегда возвращающих хэши/массивы - это то, что это проще для тех, кто не понимает ссылок или кому неудобно работать с ними. Учитывая, что комфорт с рекомендациями развивается за несколько недель или месяцев, за которыми следуют годы или десятилетия беглой работы с ними, я не считаю это значимым преимуществом.

2
ответ дан 3 December 2019 в 13:23
поделиться

Почему бы не вернуть оба? Контекст - это очень мощная функция в Perl, позволяющая вашим функциям "делать то, что вы имеете в виду". Часто решение о том, какое значение возврата лучше, зависит от того, как код вызова планирует использовать это значение, именно поэтому в Perl есть встроенный wantarray.

sub build_hash {
    my %hash;
    @hash{@keys} = (1) x @keys;
    wantarray ? %hash : \%hash
}

my %hash = build_hash;  # list context, a list of (key => value) pairs
my $href = build_hash;  # scalar context, a hash reference
9
ответ дан 3 December 2019 в 13:23
поделиться

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

8
ответ дан 3 December 2019 в 13:23
поделиться

Вы ищете кусочек хэша :

# assigns the value 1 to every element of the hash

my %hash;                                   # declare an empty hash
my @list = qw(hi bi no th xc ul 8e r);      # declare the keys as a list
@hash{@list} =                              # for every key listed in @list,
                (1) x @list;                # ...assign to it the corresponding value in this list
                                            # which is (1, 1, 1, 1, 1...)  (@list in scalar context
                                            #   gives the number of elements in the list)

Оператор x описан по адресу perldoc perlop.

См. perldoc perldsc и perldoc perlreftut, где приведены учебные пособия по структурам данных и справочникам (как для начинающих, так и для экспертов). Сами фрагменты хэша упомянуты в perldoc perlreftut.

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

Возвращаемые из функций значения всегда являются списками (где возвращаемый скаляр - это, по сути, список одного элемента). Хэши - это списки на Perl: Вы можете присваивать один другому взаимозаменяемо (предполагая, что список имеет четное количество элементов и нет коллизий ключей, которые привели бы к потере некоторых значений при преобразовании):

use strict; use warnings;
use Data::Dumper;

function foo
{
    return qw(key1 value1 key2 value2);
}

my @list = foo();
my %hash = foo();

print Dumper(\@list);
print Dumper(\%hash);

дает:

$VAR1 = [
          'key1',
          'value1',
          'key2',
          'value2'
        ];

$VAR1 = {
          'key2' => 'value2',
          'key1' => 'value1'
        };

PS. Я настоятельно рекомендую написать небольшие примеры программ, подобных вышеприведенным, чтобы поиграться со структурами данных и посмотреть, что произойдет. Вы можете многому научиться, экспериментируя!

5
ответ дан 3 December 2019 в 13:23
поделиться

Береги себя: a.pl возвращает список с четным количеством элементов, а не хэш. Когда вы затем присваиваете такой список хэш-переменной, хэш будет построен с элементами в четных индексах в качестве ключей, а элементы в нечетных индексах в качестве значений. [EDIT: Я всегда так считал, но sub { ... %hash } на самом деле ведет себя несколько иначе, чем sub { ... @list }. ]

По той же самой причине, построение хэша, как вы описываете, так же просто, как и:

my %hash = map { $_ => 1 } qw(hi bi no th xc ul 8e r);

Мое личное правило - избегать ссылок, если только они мне действительно не нужны (например, вложенные структуры, или когда вам действительно нужно передать ссылку на ту же самую вещь).

EDIT: (Я больше не могу нажимать на ссылку "добавить комментарий"?! Используя клавиши мыши здесь...). Я немного подумал об этом и думаю, что передавать хэш-ссылки, наверное, в конце концов, лучше, благодаря тому, как мы используем хэш. Однако, вышеприведенный абзац все еще содержит ссылки на массив.

Спасибо за ваши комментарии Шверн и Эфир.

1
ответ дан 3 December 2019 в 13:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: