将@_转换为Perl中的参数传递有什么好处?

ubu*_*lex 6 arrays perl arguments function shift

sub foo {
 $arg1 = shift @_;
 $arg2 = shift @_;
 # ...
}
Run Code Online (Sandbox Code Playgroud)

这个成语有什么好处?我只看到比较明确地有工作的缺点$_[0],$_[1]......阵列具有被移位,这是费时.它被破坏了,所以在稍后的时间点,参数已经消失了(如果你再次需要它们并且用不同的值覆盖你的$ arg1,那就很难过).

Сух*_*й27 9

移位@_很常见,OO perl所以参数可以从类的实例中分离出来,它自动作为第一个元素添加@_.

在为输入参数分配默认值时,它也可以用来少写,虽然我个人觉得它不吸引人,

sub foo {
  my $arg1 = shift // 2;
  my $arg2 = shift // 7;
  # ...
}
Run Code Online (Sandbox Code Playgroud)

与明确使用$ [0],$ 1,... 相比,我认为只有缺点

而不是使用$_[0], $_[1],@_一次分配整个数组是更好/更少的错误/更可读的实践.

my ($arg1, $arg2) = @_;
Run Code Online (Sandbox Code Playgroud)

另请注意,@_元素被别名传递给变量,因此可能会发生意外更改,

sub foo {
  $_[0] = 33;
  $_[1] = 44;
}

my ($x, $y) = (11,22);

print "($x, $y)\n";
foo($x, $y);
print "($x, $y)\n";
Run Code Online (Sandbox Code Playgroud)

产量

(11, 22)
(33, 44)
Run Code Online (Sandbox Code Playgroud)


ike*_*ami 5

$_[0]直接访问等比使用命名参数[1]更快,但是有很多理由更喜欢命名参数.

  1. 到目前为止,使用命名参数的最重要原因是作为一种文档形式.

  2. @_直接使用很难阅读,因为很难跟踪哪个参数具有什么价值.

    例如," $_[4]包含什么?是行吗?还是那样$_[5]?"

  3. 偶然使用错误的索引很容易.

    • 键入错误的数字很容易.
    • 当你想要另一个号码时,很容易想到你想要一个号码.
    • 更改子参数时很容易忽略索引.

  4. @_由于符号的数量,直接使用很难阅读.

    相比

    grep { $_[0]{$_} =~ /.../ } keys %{$_[0]}
    
    Run Code Online (Sandbox Code Playgroud)

    grep { $foos->{$_} =~ /.../ } keys %$foos
    
    Run Code Online (Sandbox Code Playgroud)
  5. 它对提供默认值很有用.

    sub f {
       my $x = shift // "abc";
       my $y = shift // "def";
       ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  6. 复制到标量有效地引入了逐个拷贝的语义,这可能很有用.

    $ perl -le'my $x=123; sub f {                  $x=456; print $_[0]; } f($x);'
    456
    
    $ perl -le'my $x=123; sub f { my $arg = shift; $x=456; print $arg;  } f($x);'
    123
    
    Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 是否是我的首选

    sub f {
       my (...) = @_;
       ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    要么

    sub f {
        my ... = shift; 
        my ... = shift;
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • @ubuplex,与明确使用`$ _ [0]`,`$ _ [1]`**相比,你的问题要求这个成语的好处**.这是一个完全不同的问题,评论不是一个问题的地方. (2认同)

Dav*_* W. 5

我同意所有观点。但基本问题仍然存在:为什么我应该转移而不是进行列表分配或一系列标量分配?

既然我做了换档,我会解释我为什么这样做。

您可以通过三种方式处理子程序的参数:

方法一:列表赋值

 sub foo {
    my ( $user, $date, $system ) = @_;   # No shifting, and @_ preserved
Run Code Online (Sandbox Code Playgroud)

方法 2:来自@_ 的单独赋值

 sub foo {
    my $user   = $_[1];  
    my $date   = $_[2];   # Must be YYYY-MM-DD
    my $system = $_[3];   # Optional
Run Code Online (Sandbox Code Playgroud)

方法 3:使用“移位”

sub foo {
    my $user    = shift;
    my $date    = shift;    # Must be YYYY-MM-DD
    my $system  = shift;    # Optional
Run Code Online (Sandbox Code Playgroud)

方法1流行。Ikegami 使用它,许多其他高级 Perl 开发人员也使用它。它为您提供了一个参数列表,并为您提供了一种方式来说明这些是我的参数而不是其他参数

但是,方法 2方法 3为您提供了一个漂亮的、易于阅读的参数列表,您可以在行尾添加注释。不过方法2也有保持 值的优点,那@_为什么要用shift呢?

再看看方法2。看到问题了吗?我开始与@_[1]不与@_[0]- 一个常见的错误。另外,在开发子程序时,您可能决定对参数重新排序。使用方法 2意味着对它们重新编号。方法 3不需要重新编号,因此您不会以这样的方式结束:

 sub foo {
    my $date   = $_[1];   # Must be YYYY-MM-DD
    my $user   = $_[0];  
    my $system = $_[2];   # Optional
Run Code Online (Sandbox Code Playgroud)

嗯,参数的顺序又是什么?

那么,如何保留 的价值@_呢?如果您编写一个程序来更改参数的值,则您可能不会从@_. 而且,如果你这样做,你很可能会产生一些容易出错的代码。如果你需要修改一个参数,把它放在另一个变量中并修改它。这不是 1975 年,当时计算机只有 4 KB 的内存。

而且,谈到 1970 年代,计算机的速度足够快,以至于几次(数十、数百、数千)轮班操作的时间不会对您的总运行时间产生太大影响。如果您的程序效率低下,请在效率低下的地方对其进行优化,而不是通过可能减少几毫秒来消除班次。比实际运行程序花费更多的时间来维护您的程序。


Damian Conway(Perl Best Practices的作者)推荐Method #1Method #3。他指出方法#1“......更简洁,它将参数放在一个水平列表中,这增强了可读性,前提是参数数量很少。(重点是我的)。

Damian 谈到方法#3“但是,当一个或多个参数必须经过完整性检查或需要用尾随注释记录时,基于班次的版本是更可取的。”

我只是一直使用方法#3。这样,如果我的参数列表增长,我不必担心重新格式化,我只是认为它看起来更好。