【问题标题】:Parameters passing style in PerlPerl中的参数传递样式
【发布时间】:2010-07-30 10:00:52
【问题描述】:

我看到人们在 Perl 中使用两种风格来传递命名参数:

use strict;
use warnings;
use Data::Dumper;

sub foo {
    print Dumper @_;
}

sub bar {
    print Dumper @_;
}

foo( A => 'a', B => 'b' );
bar( { A => 'a', B => 'b' } );

使用 foo() 样式代替 bar() 样式有什么好处?

【问题讨论】:

    标签: perl parameters


    【解决方案1】:

    第二种方法传递对哈希的引用,而第一种方法只是传递一个列表。

    这里有两个方面:理论上,对 hash 的引用在性能方面可能会更好,尽管对于短参数列表来说这可以忽略不计。对于像foo(a => 1, b => 2) 这样的简单调用,没有性能差异,因为@_ 实际上是原始值的别名。

    但是如果调用者已经有散列中的值,第一种样式需要从散列转换为列表,然后再返回到散列,这可能会很慢。

    第二个方面是谁负责转换为哈希的问题。第一种风格将它留给被调用的函数,如果只是这样做my %args = @_,如果参数列表的长度不均匀,它会产生奇怪的警告。

    这就是为什么我更喜欢第二种风格(或者我使用 Perl 6,它本机支持命名参数)。

    【讨论】:

    • 这些“性能方面”是不必要的微优化,不会产生任何实际好处。哈希可以像列表一样简单地使用:foo(%hash) 或哈希引用:foo(%{$hashref})。坚持 foo 风格会给用户更多的权力。
    • 实际上,我自己的基准测试表明(在多个安装中)传递列表比传递引用更快——尽管它似乎更快地返回引用。
    • 警告是比可疑的性能声明更好的理由,但如果您在运行时生成一部分参数,它实际上并不能真正保护您。
    【解决方案2】:

    foo(a => 1, b => 2) 样式是模拟命名参数的常用方法。 bar({a => 1, b => 2}) 通常仅用于补充(并且可能是可选的)参数。

    对于典型用法,我更喜欢第一种形式。 {} 是额外的打字,额外的阅读噪音,如果你遗漏一个或两个大括号,可能会产生错误。任何性能差异都可以忽略不计。 (如果不是,则问题更大。)另一方面,将参数包装在匿名哈希构造函数中可以帮助您在编译时而不是运行时发现错误。

    第二种形式通常与位置参数混合使用。例如基准是这样做的:

    cmpthese(10000, {
        foo => \&foo,
        bar => \&bar,
    });
    

    当 Tk 离开 {} 时:

    my $text = $w->Scrolled('Text', -width => 80, -height => 50);
    

    这通常是一种风格选择。

    【讨论】:

      【解决方案3】:

      首先解释一下这两种方法:

      sub foo {
          # Transform the array to a hash
          my %args = @_;
      
          foreach my $key ( keys %args ) {
              print "$key => $args{$key}\n";
          }
      }
      
      # Pass an array of values
      foo( A=>'a', B=>'b' );
      

      在第一种情况下,您所做的只是传递一个数组。在这种情况下,=> 不是您可能认为的哈希键/值指示符。在这种情况下,它只是一个“胖逗号”。

      sub bar {
          my ($hash_ref) = @_;
          foreach my $key ( keys %$hash_ref ) {
              print "$key => $hash_ref->{$key}\n";
          }
      }
      
      # pass a ref to an anonymous hash
      bar( { A=>'a', B=>'b' } );
      

      在第二种情况下,您将创建一个匿名哈希并将对该哈希的引用作为参数传递给函数。

      为什么选择一个而不是另一个?在《Perl 最佳实践》一书第 9 章的“命名参数”标题下,作者建议在函数参数超过三个时使用第二种样式。他也更喜欢它,因为它在编译时而不是在运行时捕获不匹配数量的参数。

      【讨论】:

      • 我已经有一段时间没有阅读它了,但我认为建议使用带有 3 个以上参数的 hashref 来代替标准的未命名参数列表,即调用 foo( 'a', 'b' ),而不是推荐使用 hashrefs 而不是散列
      • @plusplus:该部分的标题是:“对任何具有三个以上争论的子例程使用命名争论的散列。”在文章的正文中,他特别说要在转换为散列的原始名称/值对上使用散列引用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-19
      • 1970-01-01
      • 2017-09-02
      • 2018-04-07
      • 1970-01-01
      • 2012-09-09
      相关资源
      最近更新 更多