在 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 不需要复制每个值更快。当然,缺点(或优点取决于您的观点)是值保持别名,因此您无法在不更改原件的情况下更改它们。
正如tchrist在对另一个答案的评论中提到的那样,当您在 上使用 Perl 的任何别名构造时@_
,$_
它们为您提供的 the 也是原始子例程参数的别名。如:
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;
}