我正在尝试使用以下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代表什么?
答案 0 :(得分:8)
@_
是传递给函数的参数列表。通过执行my ($m,$n,$aref) = @_;
,您将$_[0]
分配给$m
,将$_[1]
分配给$n
,将$_[2]
分配给$aref
。
$aref
是一个标量值,用于保存对数组的引用。要引用数组中的元素,您可以通过$aref->[0]
(这是更惯用的)访问它们,或者通过取消引用数组引用来访问它们。通过在前面添加@
,您可以引用该数组(即@$aref
)。但是,您需要数组中的第一个元素,即标量,因此它是$$aref[0]
获得的。添加括号(${$aref}[0]
)或使用箭头符号($aref->[0]
)可以澄清这一点。
\@p
是对数组@p
的引用。由于您的函数将标量作为第三个参数,因此您必须传入标量。 \@p
就是这样。将数组引用传递给这样的函数时,重要的是要注意对数组的任何更改(例如执行$$aref[0] = $n+1
)都是对原始数组的更改。如果你想避免这种情况,你可以将数组解引用为临时数组,可能是在函数中执行my @tmparr = @$aref;
。
答案 1 :(得分:2)
首先,
my ($m,$n,$aref) = @_;
代表什么?
当您将一组参数传递给子例程时,它们将作为列表(有时称为数组)传递给名为{{1}的特殊数组}。
在这种情况下,子例程将变量@_
,$m
和$n
设置为此特殊数组中的前三个值。
与此类似:
$aref
其次,如何理解像
这样的my $m = @_[0]; my $n = @_[1]; my $aref = @_[2];
$$
现在,我们正在进入引用。引用是另一个Perl变量的指针。想象一下,我有一个这样的数组:
$$aref[0] = $n+1;
我可以通过这样做来创建指向此列表的指针:
@my_list = ("one", "two", "three", "four");
变量my $my_list_ref = \@my_list;
现在指向$my_list_ref
。变量@my_list
之前的反斜杠告诉Perl我不想让@my_list
等于$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
将引用变量放在大括号中有助于澄清您正在做的事情,但同时,它可能会使解析变得更加困难。为了解决这个问题,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'
语法,即preferred coding style:
->
这个函数被调用为
print $my_list_ref->[0]; #Prints 'one' print $my_list_ref->[1]; #Prints 'two'
inittwiddle($M,$N,\@p);
代表什么?
现在,我们开始讨论为什么要首先使用引用。首先,我们来看看Perl子例程的一些限制:
\@p
数组中传递。如果我有一个以两个列表作为参数的子程序怎么办?他们都被打成单个@_
数组。@_
数组中。使用引用可以解决所有这些问题。编写此子例程的开发人员正试图解决问题#2和问题#3。电话:
@_
正在使用两个标量变量,以及对数组inittwiddle($M, $N, \@p);
的引用。如果数组@p
中有一百万个值,则可能需要很长时间才能将整个列表复制到子例程中。此外,开发人员看起来他们也在更改@p
中的项目。当开发人员说:
@p
他实际上正在将$$aref[0] = $n + 1;
更改为$p[0]
。子例程返回时,$n + 1
将具有与子例程之前不同的值。请注意,$p[0]
不仅仅是@$aref
的副本,它指向@p
,因此它是@p
。
您应该阅读Perl Reference Tutorial以获取有关参考的更多信息。
答案 2 :(得分:1)
第一个问题就是论证传递。调用perl sub时,它的参数位于特殊数组@_
中。第一行只占用数组中的前3项,并将它们放在这3个局部变量中。
另外两个问题涉及参考。我建议你看一下perlref manpage。 \@p
正在传递数组@p
的引用。然后,将该引用放在$aref
中,然后使用$$aref[0]
访问数组的第一个元素(可能更清楚地将其视为${$aref}[0]
)。