为什么从@_移位值不是别名?

时间:2018-05-23 14:55:26

标签: perl parameter-passing subroutine

  

shift
  将数组的第一个值移开并返回...

这样做是为了速度优化并避免按值复制。

同样在perlsub

  

数组@_是一个本地数组,但其元素是实际标量参数的别名。特别是,如果更新元素$ _ [0],则更新相应的参数

因此,如果我们在sub中执行my $self = shift,我们会将第一个值从@_移位,这是一个别名,不是吗?

但是当我们比较这两个时:

sub test {
     print \$_[0];    # SCALAR(0xf73c38)
     my $x =  shift;
     print \$x;       # SCALAR(0xf79800)
}

我们看到$x是副本。

为什么来自@_的shift ed值不是别名?

因此,如果为案例my $x = shift复制了值,那么它对my $x = $_[0]提供了哪些好处?

2 个答案:

答案 0 :(得分:9)

移位的值是别名

$ perl -E 'sub F{say \$_[0]; say \shift} $x=42; say \$x; F($x)'
SCALAR(0x1d7f1e0)
SCALAR(0x1d7f1e0)
SCALAR(0x1d7f1e0)

分配操作(例如$x = $_[0]$x = shift)会在右侧创建标量的副本,因此新分配的值不再是别名。

正如工具所说,shift的好处是修改@_,这有时会使你在子程序的其余部分中更容易使用。

如果您仍希望能够修改输入

,仍然可以使用引用来移位值
$ perl -E 'sub G { my $x=\shift; $$x = 19 } my $z = 42; G($z); say $z'
19

答案 1 :(得分:3)

shift不是左值运算符。

$ perl -e'
   use feature qw( say );
   sub f { shift = 456; }
   { my $x = 123; f($x); say $x; }
'
Can't modify shift in scalar assignment at -e line 3, near "456;"
Execution of -e aborted due to compilation errors.

但是,从@_转移的值仍然是别名。

$ perl -e'
   use feature qw( say );
   sub f { my $p = \shift; $$p = 456; }
   { my $x = 123; f($x); say $x; }
'
456

$ perl -e'
   use feature qw( say );
   sub f { ${ \shift } = 456; }
   { my $x = 123; f($x); say $x; }
'
456

问题是你将别名数组元素的值赋给$x而不是将$x别名化为数组元素。如果要命名@_的元素,则需要为其添加变量。

$ perl -e'
   use feature qw( say );
   sub f { our $x; local *x = \shift; $x = 456; }
   { my $x = 123; f($x); say $x; }
'
456

$ perl -e'
   use feature qw( say );
   use Data::Alias qw( alias );
   sub f { alias my $x = shift; $x = 456; }
   { my $x = 123; f($x); say $x; }
'
456

$ perl -e'
   use feature qw( say refaliasing );
   no warnings qw( experimental::refaliasing );
   sub f { \my $x = \shift; $x = 456; }
   { my $x = 123; f($x); say $x; }
'
456

my $x = shift优于my $x = $_[0];的好处很多,虽然很小。

  • shift$_[0]更容易输入。
  • 当有多个参数时,您可以使用shift而不是保持计数。
  • shift支持复杂和开放式参数列表。 (例如sub f { my $cb = shift; $cb->($_) for @_; }
  • shift在显微镜下比$_[0](IIRC)更快。