首先,这是什么my ($m,$n,$aref) = @_;
立场?
当您通过一组参数到一个子程序,他们正在为列表传递(有时称为数组)到一个名为@_
特殊的数组。
在这种情况下,子例程将变量$m
,$n
和$aref
设置为此特殊数组中的前三个值。
它类似于此:
my $m = @_[0];
my $n = @_[1];
my $aref = @_[2];
其次,如何理解$$
讨价还价像$$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'
注意双美元符号!这是你在子程序中看到的。
大多数时候,你会看到->
语法,这是preferred coding style:
print $my_list_ref->[0]; #Prints 'one'
print $my_list_ref->[1]; #Prints 'two'
而这个函数被调用为inittwiddle($M,$N,\@p);
什么\@p
立场?
现在,我们进入了问题,为什么你会在第一个地方使用引用。首先,我们来看看Perl子程序的一些局限性:
- 所有参数都在一个单一的
@_
数组中传递。如果我有一个以两个列表作为参数的子程序呢?他们都得到了单一的@_
阵列。
- 如果我在我的子程序中传入一个非常大的列表,这可能需要很多内存,因为该列表被复制到
@_
阵列中。
- 在Perl子例程中,我传递的所有变量在子例程中都有独立的标识。在子程序中更改它们不会在离开子程序后更改它们的值。如果我想改变他们的价值呢?
使用参考可以解决所有这些问题。编写该子程序的开发人员正在试图解决问题#2和问题#3。召唤:
inittwiddle($M, $N, \@p);
走的是两条标变量,及阵列@p
参考。如果数组@p
中有100万个值,则可能需要很长时间才能将整个列表复制到子例程。此外,开发人员看起来像他们也在更改@p
中的项目。当开发人员说:
$$aref[0] = $n + 1;
他实际上改变$p[0]
到$n + 1
。当子程序返回时,$p[0]
将具有与子程序之前不同的值。请记住,@$aref
不只是@p
的副本,它指向@p
,因此它是@p
。
有关引用的更多信息,您应该阅读Perl Reference Tutorial。
对于初学者来说,注意由于'@ p'是通过引用传入的,所以'$$ aref []]的赋值在'@ p'数组中被赋值。 – 2012-02-09 22:26:23
@EricStrom:这是一个很好的观点。我已经扩大了#3以覆盖这一点。 – CanSpice 2012-02-09 22:34:16
差不多。 '@ _'表示传递给函数的参数列表,但它不是单词Perl意义上的“列表”,而是一个数组。 '@ _'指的是一个数组,其值*是参数列表中的值,即不是*参数列表中的值的副本,它们*是参数列表中的值。所以如果你用'foo($ a)'调用一个sub,那么在sub内部,'$ _ [0]'指的是与'$ a'在外部相同的标量值,也就是说, $ _ [0]'和外部的'$ a'是同一个标量值的别名。 – zgpmax 2012-02-10 12:05:48