Стиль передачи параметров в Perl

Я вижу людей, использующих два стиля для передачи именованных параметров в Perl:

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

sub foo {
    print Dumper @_;
}

sub bar {
    print Dumper @_;
}

foo( A => 'a', B => 'b' );
bar( { A => 'a', B => 'b' } );

Каковы преимущества использования стиля foo() вместо стиля bar()?


person Howard    schedule 30.07.2010    source источник


Ответы (3)


Второй метод передает ссылку на хэш, а первый просто передает список.

Здесь есть два аспекта: теоретически ссылка на хэш могла бы быть лучше с точки зрения производительности, хотя для коротких списков аргументов это незначительно. Для простого вызова, такого как foo(a => 1, b => 2), разницы в производительности нет, потому что @_ на самом деле является псевдонимом исходных значений.

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

Второй аспект — это вопрос, кто отвечает за преобразование в хэш. Первый стиль оставляет вызываемую функцию наверху, и если это просто делает my %args = @_, он выдаст любопытные предупреждения, если список аргументов имеет нечетную длину.

Вот почему я немного предпочитаю второй стиль (или я использую Perl 6, который изначально поддерживает именованные аргументы).

person moritz    schedule 30.07.2010
comment
Эти аспекты производительности являются ненужными микрооптимизациями, которые не приносят практической пользы. Хэш можно использовать так же просто, как список: foo(%hash) или хэш-ссылку: foo(%{$hashref}). Придерживаясь стиля foo, пользователь получает больше возможностей. - person jmz; 30.07.2010
comment
На самом деле, мой собственный бенчмаркинг показал (на нескольких установках), что быстрее передавать списки, чем ссылки, хотя возврат ссылок оказывается быстрее. - person Axeman; 30.07.2010
comment
Предупреждения - лучшая причина, чем сомнительные заявления о производительности, но если вы генерируете фрагмент аргументов во время выполнения, в любом случае это на самом деле не так уж сильно вас защищает. - person ; 31.07.2010

Стиль foo(a => 1, b => 2) — это обычный способ эмуляции именованных аргументов. bar({a => 1, b => 2}) обычно используется только для дополнительных (и, возможно, необязательных) аргументов.

Для типичного использования я предпочитаю первую форму. {} — это лишний набор текста, лишний шум при чтении и создание возможной ошибки, если вы пропустите одну или обе фигурные скобки. Любая разница в производительности незначительна. (Если это не так, у вас большие проблемы.) С другой стороны, помещение аргументов в анонимный хэш-конструктор может помочь вам найти ошибки во время компиляции, а не во время выполнения.

Вторая форма обычно встречается в сочетании с позиционными аргументами. например Бенчмарк делает это:

cmpthese(10000, {
    foo => \&foo,
    bar => \&bar,
});

В то время как Tk оставляет {} вне:

my $text = $w->Scrolled('Text', -width => 80, -height => 50);

Обычно это стилистический выбор.

person Michael Carman    schedule 30.07.2010

Во-первых, объяснение двух методов:

sub foo {
    # Transform the array to a hash
    my %args = @_;

    foreach my $key ( keys %args ) {
        print "$key => $args{$key}\n";
    }
}

# Pass an array of values
foo( A=>'a', B=>'b' );

В этом первом случае все, что вы делаете, это передаете массив. => в этом контексте не является индикатором ключа/значения хэша, как вы могли бы подумать. В данном контексте это просто "жирная запятая".

sub bar {
    my ($hash_ref) = @_;
    foreach my $key ( keys %$hash_ref ) {
        print "$key => $hash_ref->{$key}\n";
    }
}

# pass a ref to an anonymous hash
bar( { A=>'a', B=>'b' } );

Во втором случае вы создаете анонимный хэш и передаете ссылку на этот хеш в качестве аргумента функции.

Зачем выбирать одно над другим? В книге Perl Best Practices, глава 9 под заголовком «Именованные аргументы», автор рекомендует использовать второй стиль, когда у функции более трех аргументов. Он также предпочитает его, потому что он улавливает несоответствие количества аргументов во время компиляции, а не во время выполнения.

person Robert S. Barnes    schedule 30.07.2010
comment
я давно это читал, но я думал, что рекомендация использовать хеш-ссылку с 3+ аргументами была вместо стандартного списка безымянных аргументов, т.е. вызов foo( 'a', 'b' ), а не рекомендация хэш-ссылки вместо хэшей - person plusplus; 30.07.2010
comment
@plusplus: заголовок раздела: используйте хеш именованных аргументов для любой подпрограммы, которая имеет более трех аргументов. В теле статьи он специально говорит использовать хеш-ссылку поверх необработанных пар имя/значение, преобразованных в хэш. - person Robert S. Barnes; 30.07.2010