Perl — передача аргументов подпрограмме как проблема с парами хеш-значений

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

Пример:

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

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

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

Спасибо.

KK


person kk.    schedule 01.12.2009    source источник
comment
Вы также можете лучше понять проблемы и различные варианты, связанные с этим вопросом: stackoverflow.com/questions/803808/   -  person Ya. Perelman    schedule 01.12.2009


Ответы (1)


Пояснения

да. Этот синтаксис является правильным и идиоматичным для 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
comment
Хорошее объяснение, тем более что вы не отговаривали и не жаловались на то, что не знаете, что делает код ОП. - person Andrew Barnett; 01.12.2009
comment
Большое спасибо, Яаков. Я не дал полного описания проблемы, потому что кто-то может дать весь код, который я хочу сделать сам. Через день выложу код для проверки. Еще раз спасибо. :) - person kk.; 01.12.2009