Пояснения
да. Этот синтаксис является правильным и идиоматичным для 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 --- вам нужно посмотреть на ее реализацию или спросить человека, который посоветовал вам ее использовать. Также возможно, что по общему соглашению все высокоуровневые функции в каком-то проекте используют этот стиль вызова, даже если некоторые из них не предоставляют особых возможностей.
person
Yaakov Belch
schedule
01.12.2009