Perl - передача аргументов в подпрограмму как проблема пар хэш-ключ-значение - PullRequest
5 голосов
/ 01 декабря 2009

Я должен передать две ссылки в качестве аргументов подпрограмме (buildRanges) в виде пар хеш-ключ-значение, как показано ниже

Пример:

@array = (“0A0”, “005”, “001”, “004”, “0BC”, “004”, “002”, “001”);
@ranges = ();
$numRanges = buildRanges(VALUES => \@array, REF_RANGES=>\@ranges);

Мой вопрос
1. правильный ли синтаксис для вызова подпрограммы, приведенного выше?
2. что такое VALUES и REF_RANGES?

Честно говоря, я не мог понять подпрограммный вызов, но мне сказали использовать только этот вызов.

Спасибо.

KK

1 Ответ

28 голосов
/ 01 декабря 2009

Пояснения

Да. Этот синтаксис является правильным и идиоматическим для Perl. Давайте разберем все части вашего вызова функции - скорее всего, вы уже знаете части объяснения.

Подготовка: ваши входные данные

@array = (“0A0”, “005”, “001”, “004”, “0BC”, “004”, “002”, “001”);
@ranges = ();
# \@array and \@ranges are now normal scalar references.

Надеюсь, вы понимаете концепцию ссылок на массивы. Если нет, прочитайте perlreftut или perllol . На самом деле, это не влияет на синтаксис вызова, о котором вы спрашиваете. Кстати, вы могли бы также написать:

$array_ref=[“0A0”, “005”, “001”, “004”, “0BC”, “004”, “002”, “001”];
$range_ref=[];

$numRanges = buildRanges(VALUES => $array_ref, REF_RANGES=> $range_ref);

вызов функции

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

$numRanges = buildRanges(VALUES => $array_ref, REF_RANGES => $range_ref);
$numRanges = buildRanges("VALUES", $array_ref, "REF_RANGES", $range_ref);

Итак, вы просто вызываете функцию buildRanges с четырьмя аргументами: двумя константными строками и двумя ссылками на массивы. Вы заметили, что слово VALUES было изменено на постоянную строку "VALUE"; то же самое относится и к слову REF_RANGES. Это специальное правило: перед стрелкой => и внутри фигурных скобок {} простые идентификаторы автоматически преобразуются в строки. Мы видим это снова ниже. Но другие выражения, такие как $ a => $ b, остаются без изменений, здесь не происходит тихого преобразования в строки.

Возможно, вы спрашиваете, почему Perl делает это? Это синтаксический сахар : оператор => не делает ничего, что вы не могли бы сделать без него легко. Но для опытных программистов на Perl формат KEY => $ value выглядит яснее, чем "KEY", $ value.

Определение функции

Определение функции buildRanges может выглядеть следующим образом (и мы используем это в нашем объяснении):

sub buidRanges { my(%info)=@_; 
  my $values    = $info{VALUES};
  my $ref_ranges= $info{REF_RANGES};
  my $special_feature = $info{SPECIAL_FEATURE}; # explained below
  if($special_feature) { ... return special_result; }
  ... process $values and $ref_ranges ... return $numRanges.
}

С вашими входными данными каждая из следующих четырех строк имеет одинаковый эффект:

my(%info)=@_;                                          # the actual code
my(%info)=(VALUES => \@array, REF_RANGES=> \@ranges ); # what this does

my %info; $info{"VALUES"}=\@array; $info{"REF_RANGES"}=\@ranges; 
my %info; $info{ VALUES }=\@array; $info{ REF_RANGES }=\@ranges; 

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

Выберите одну понятную вам строку и сравните ее с другими: они делают то же самое. Посмотрите на perldsc для получения дополнительных объяснений.

Обратите внимание, что @_ это массив входных аргументов, в нашем случае

@_ = ( VALUES => \@array, REF_RANGES=> \@ranges); 
@_ = ("VALUES",  \@array,"REF_RANGES", \@ranges);  # without syntactic sugar

Возможно, вы заметили, что $ info {VALUES} эквивалентно $ info {"VALUES"} - опять же, это синтаксический сахар, как объяснено выше.

Далее в нашей гипотетической реализации мы извлекаем входные данные из хеша:

 my $values     = $info{VALUES};       # i.e:  my $value      = \@array;
 my $ref_ranges = $info{REF_RANGES};   # i.e:  my $ref_renges = \@ranges;

Теперь наша реализация функции может работать с входными данными.

Почему мы делаем это не проще? --- Именованные аргументы

Пока что мы могли бы добиться аналогичного эффекта намного проще:

$numRanges = buildRanges($array_ref, $range_ref);  # simpler function call

sub buidRanges { my($values, $ref_ranges)=@_; 
  ... process $values and $ref_ranges ... return $numRanges.
}

Скорее всего, это стиль программирования, который вы уже хорошо понимаете.

Итак: зачем некоторым программистам на Perl усложнять (и гораздо медленнее)? Ответ таков: он более гибкий и несколько самодокументируемый.

Чтобы прояснить ситуацию, я добавил SPECIAL_FEATURE в определение нашей функции. Теперь функцию также можно вызвать так:

$numRanges = buildRanges(VALUES => \@array, SPECIAL_FEATURE=> "infinite ranges");

Реализованная функция может сказать, что запрашивается SPECIAL_FEATURE и что REF_RANGES не предоставляются.

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

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

...