три вопроса о существующей подпрограмме Perl - PullRequest
3 голосов
/ 10 февраля 2012

Я пытаюсь использовать следующую функцию perl, но мне не очень ясно о трех моментах:

sub inittwiddle { 
    my ($m,$n,$aref) = @_; 
    my $i; 
    $$aref[0] = $n+1; 
    for ($i=1; $i != $n-$m+1; $i++) { 
       $$aref[$i] = 0; 
    } 
    while($i != $n+1) { 
       $$aref[$i] = $i+$m-$n; 
       $i++; 
    } 
    $$aref[$n+1] = -2; 
    $$aref[1] = 1 if ( $m == 0 ); 
} 

Во-первых, что означает my ($m,$n,$aref) = @_;?

Во-вторых, как понять $$ для чего-то вроде $$aref[0] = $n+1;

И эта функция была вызвана как inittwiddle($M,$N,\@p); что означает \ @p?

Ответы [ 3 ]

8 голосов
/ 10 февраля 2012
  1. @_ - список аргументов, переданных функции. Делая my ($m,$n,$aref) = @_;, вы назначаете $_[0] на $m, $_[1] на $n и $_[2] на $aref.

  2. $aref - скалярное значение, содержащее ссылку на массив. Чтобы обратиться к элементам в массиве, вы можете получить к ним доступ через $aref->[0] (это более идиоматично) или путем разыменования ссылки на массив. Добавив @ вперед, вы бы обратились к массиву (т.е. @$aref). Тем не менее, вам нужен первый элемент в массиве, который является скаляром, поэтому он получается как $$aref[0]. Добавление скобок (${$aref}[0]) или использование обозначения стрелки ($aref->[0]) немного проясняет это.

  3. \@p является ссылкой на массив @p. Поскольку ваша функция принимает скаляр в качестве третьего аргумента, вы должны передать скаляр. \@p такой. Когда вы передаете ссылку на массив в функцию, подобную этой, важно отметить, что любые изменения в массиве (например, выполнение $$aref[0] = $n+1) - это изменения исходного массива. Если вы хотите избежать этого, вы можете разыменовать массив во временный, возможно, выполнив my @tmparr = @$aref; внутри функции.

2 голосов
/ 10 февраля 2012

Во-первых, что означает my ($m,$n,$aref) = @_;?

Когда вы передаете набор аргументов в подпрограмму, они передаются как список (иногда называемый массивом ) в специальный массив с именем @_.

В этом случае подпрограмма устанавливает переменные $m, $n и $aref впервые три значения в этом специальном массиве.

Это похоже на это:

my $m = @_[0];
my $n = @_[1];
my $aref = @_[2];

Во-вторых, как понять $$ для sth как $$aref[0] = $n+1;

Теперь мы переходим к ссылкам .Ссылкой является указатель на другую переменную Perl.Представьте, что у меня есть такой массив:

@my_list = ("one", "two", "three", "four");

Я могу создать указатель на этот список, выполнив следующее:

my $my_list_ref = \@my_list;

Переменная $my_list_ref теперь указывает на @my_list.Обратная косая черта перед переменной @my_list говорит Perl, что я не хочу делать $my_list_ref равным @my_list.Вместо этого я просто хочу, чтобы от $my_list_ref до указывали на @my_list.

Теперь, если я действительно хочу сослаться на данные, на которые указывает $my_list_ref, я делаю то, что называется разыменование это.Я делаю это, помещая перед ним @:

print join ",", @{ $my_list_ref };   #prints "one, two, three, four"

И если я хочу сослаться на конкретное значение в списке, на который указывает $my_list_ref, я могу сделать тот же типсинтаксис:

print ${ $my_list_ref }[0];   #Prints 'one'
print ${ $my_list_ref }[1];   #Prints 'two'

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

В простых случаях вы можете удалить фигурные скобки:

print $$my_list_ref[0];   #Prints 'one'
print $$my_list_ref[1];   #Prints 'two'

Обратите внимание на двойной знак доллара!Это то, что вы видите в своей подпрограмме.

В большинстве случаев вы увидите синтаксис ->, который является предпочтительным стилем кодирования :

print $my_list_ref->[0];  #Prints 'one'
print $my_list_ref->[1];  #Prints 'two'

И эта функция была вызвана как inittwiddle($M,$N,\@p); что означает \@p?

Теперь мы переходим к вопросу, почему вы будете использовать ссылки в первую очередь.Во-первых, давайте рассмотрим некоторые ограничения подпрограмм Perl:

  1. Все параметры передаются в одном массиве @_.Что если у меня есть подпрограмма, которая принимает два списка в качестве параметров?Они оба объединяются в один массив @_.
  2. Если я передаю действительно большой список в мою подпрограмму, это может занять много памяти, так как этот список копируется в массив @_.
  3. В подпрограмме Perl все переменные, которые я передаю, имеют независимые идентификаторы в подпрограмме.Изменение их в подпрограмме не меняет их значений после выхода из подпрограммы.Что делать, если я хочу изменить их значения?

Использование ссылки решает все эти проблемы.Разработчик, написавший эту подпрограмму, пытался решить и проблему № 2, и проблему № 3.Вызов:

inittwiddle($M, $N, \@p);

принимает две скалярные переменные и ссылку на массив @p.Если в массиве @p содержится миллион значений, копирование всего списка в подпрограмму может занять много времени.Кроме того, разработчик выглядит так, будто они также меняют элементы в @p.Когда разработчик говорит:

$$aref[0] = $n + 1;

Он фактически меняет $p[0] на $n + 1.Когда подпрограмма вернется, $p[0] будет иметь значение, отличное от того, что было до подпрограммы.Помните, что @$aref не просто дубликат @p, он указывает на @p, поэтому это @p.

Вы должны прочитать Справочник Perl длябольше информации о ссылках.

1 голос
/ 10 февраля 2012

Первый вопрос - просто передача аргументов.Когда вызывается sub per, аргументы к нему находятся в специальном массиве @_.Первая строка просто берет первые 3 элемента в массиве и помещает их в эти 3 локальные переменные.

Два других вопроса связаны со ссылками.Я рекомендую взглянуть на справочную страницу perlref .\@p передает ссылку на массив @p.Затем эта ссылка помещается в $aref, а затем к первому элементу массива осуществляется доступ с помощью $$aref[0] (что, возможно, будет более понятным для чтения как ${$aref}[0]).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...