在Perl中,存储在
@_
中的子例程参数始终是调用点处值的别名。这种别名仅在
@_
中持续存在,如果您将值拷贝出来,那么您得到的就是值。
因此,在这个子程序中:
sub example {
# @_ is an alias to the arguments
my ($x, $y, @rest) = @_; # $x $y and @rest contain copies of the values
my $args = \@_; # $args contains a reference to @_ which maintains aliases
}
请注意,这种别名现象在列表扩展后发生。如果您将数组传递给
example
,则该数组在列表上下文中扩展,并且
@_
设置为该数组每个元素的别名(但是数组本身对
example
不可用)。如果您想要修改数组本身,可以传递一个数组的引用。
子例程参数的别名是非常有用的功能,但必须小心使用。为了防止意外更改外部变量,在Perl 6中,您必须指定带
is rw
的可写别名参数。
其中一个较少知道但实用的技巧是使用此别名特性创建数组别名的引用。
my ($x, $y) = (1, 2);
my $alias = sub {\@_}->($x, $y);
$$alias[1]++; # $y is now 3
或者别名切片:
my $slice = sub {\@_}->(@somearray[3 .. 10]);
事实证明,使用sub {\@_}->(LIST)
从列表创建数组比[ LIST ]
更快,因为Perl不需要拷贝每个值。当然,缺点(或优点,取决于您的观点)是这些值保持别名关系,因此您无法改变它们而不改变原始值。
正如其他回答中在评论中提到的,当您在@_
上使用Perl的任何别名构造时,它们提供给您的$_
也是指向原始子例程参数的别名。例如:
sub trim {s!^\s+!!, s!\s+$!! for @_} # in place trimming of white space
最后,所有这些行为都是可以嵌套的,因此当在另一个子例程的参数列表中使用@_
(或其切片)时,它也会被赋予第一个子例程参数的别名:
sub add_1 {$_[0] += 1}
sub add_2 {
add_1(@_) for 1 .. 2;
}
@_
而不是$_
。在sub
中,@_
通常包含别名而不是值的副本。因此,如果您不希望在sub
中出现这种行为,请确保在开始时将输入从@_
复制到my
变量中。 - aschepler