【问题标题】:Why shifted value from @_ is not alias?为什么从@_ 转移的值不是别名?
【发布时间】:2026-01-23 00:30:01
【问题描述】:

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

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

同样在perlsub

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

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

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

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

我们看到$x 是副本。

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

因此,如果也为案例my $x = shift 复制该值,那么与my $x = $_[0] 相比,它有什么好处?

【问题讨论】:

    标签: perl parameter-passing subroutine


    【解决方案1】:

    移位后的值是别名

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

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

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

    如果您仍然希望能够修改输入,您仍然可以使用对移位值的引用

    $ perl -E 'sub G { my $x=\shift; $$x = 19 } my $z = 42; G($z); say $z'
    19
    

    【讨论】:

    • 那么$x=shift$x=$_[0] 有什么好处?
    • 如果我理解正确,shift 的变体会更慢,但如果稍后将@_ 传递到基类,我可能会受益
    • 不知道shift是不是很慢。 shift @foo@foo 的修改不大,只需移动代表数组前面的指针即可。
    • shift 的优势在于您传递不同类型的东西。例如:my $self = shift; 面向对象时,@_ 的其余部分是“参数”。
    • 考虑 sub append_all { my $with=shift; map "$_$with", @_ }sub append_all { my $with=$_[0]; map "$_$with", @_[1..$#_] } 我认为显然第一个更容易阅读和理解。
    【解决方案2】:

    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) 快。

    【讨论】:

      最近更新 更多