关于现有perl子例程的三个问题

时间:2012-02-09 22:14:03

标签: perl

我正在尝试使用以下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 个答案:

答案 0 :(得分:8)

  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;

答案 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子例程的一些限制:

  1. 所有参数都在一个\@p数组中传递。如果我有一个以两个列表作为参数的子程序怎么办?他们都被打成单个@_数组。
  2. 如果我将一个非常非常大的列表传递到我的子例程中,那可能会占用大量内存,因为该列表被复制到@_数组中。
  3. 在Perl子例程中,我传递的所有变量在子例程中都具有独立的标识。一旦离开子程序,在子程序中更改它们就不会改变它们的值。如果我想改变他们的价值怎么办?
  4. 使用引用可以解决所有这些问题。编写此子例程的开发人员正试图解决问题#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])。