【问题标题】:Default argument values in subroutines子例程中的默认参数值
【发布时间】:2010-08-22 21:49:50
【问题描述】:

我不知道如何为子程序设置默认参数。这是我考虑的:

sub hello {
  print @_ || "Hello world";
}

如果您只需要一个参数,这很好用。您将如何为多个参数设置默认值?

我打算这样做:

sub hello {
  my $say = $_[0] || "Hello";
  my $to  = $_[1] || "World!";
  print "$say $to";
}

但这是很多工作......必须有一个更简单的方法;可能是最佳实践?

【问题讨论】:

    标签: perl function subroutine


    【解决方案1】:

    我用这样的命名参数来做:

    sub hello {
        my (%arg) = (
            'foo' => 'default_foo',
            'bar' => 'default_bar',
            @_
        );
    
    }
    

    我相信Params::Validate 支持默认值,但这比我愿意承担的麻烦更多。

    【讨论】:

      【解决方案2】:

      我通常会这样做:

      sub hello {
          my ($say,$to) = @_;
          $say ||= "Hello";
          $to ||= "World!";
          print "$say $to\n";
      }
      

      请注意,从 perl 5.10 开始,您可以使用“//=”运算符来测试变量是否已定义,而不仅仅是非零。 (想象一下调用hello("0","friend"),使用上面的会产生"Hello friend",这可能不是你想要的。使用//= 运算符会产生"0 friend"

      【讨论】:

      • @Davidmoreen:测试数组的定义性没有用
      • @Davidmoreen,正确的说法是print $_[0] // "Hello world";。正如 ysth 所说,您不能在数组上使用 defined(这是 // 的意思),因为标量上下文中的数组返回其长度,该长度始终是定义的。
      【解决方案3】:

      还可以查看Method::Signatures。这使用Devel::Declare 来提供一些额外的(需要的!)糖与关键字methodfunc

      以下是您使用新 func 的示例:

      use Method::Signatures;
      
      func hello ($say='Hello', $to='World!') {
          say "$say $to";
      }
      
      hello( 'Hello', 'you!' );    # => "Hello you!"
      hello( 'Yo' );               # => "Yo World!"
      hello();                     # => "Hello World!"
      

      /I3az/

      【讨论】:

        【解决方案4】:

        因为 Perl 将参数传递给子例程的机制是单个列表,所以参数是位置的。这使得很难提供默认值。一些内置函数(例如substr)通过根据参数被使用的可能性对参数进行排序来处理这个问题——不太常用的参数出现在最后并具有有用的默认值。

        更简洁的方法是使用命名参数。 Perl 不支持命名参数本身,但你可以用哈希来模拟它们:

        use 5.010;  # for //
        
        sub hello {
            my %arg = @_;
            my $say = delete $arg{say} // 'Hello';
            my $to  = delete $arg{to}  // 'World!';
            print "$say $to\n";
        }
        
        hello(say => 'Hi', to => 'everyone');  # Hi everyone
        hello(say => 'Hi');                    # Hi world!
        hello(to  => 'neighbor Bob');          # Hello neighbor Bob
        hello();                               # Hello world!
        

        注意:定义或运算符// 是在 Perl v5.10 中添加的。它比使用逻辑或 (||) 更健壮,因为它不会默认使用逻辑错误值 ''0

        【讨论】:

          【解决方案5】:

          如果您看到 Perl Best Practices 的文档:Default argument Values by Damian Conway,那么您会发现一些重要的点,例如:

          • 解压@_ 后立即解析所有默认参数值
          • 建议如果您要设置许多默认值,那么最简洁的方法是将 默认值分解到表中,即散列,然后使用该表预初始化参数散列。

          示例:

          #!/usr/bin/perl
            use strict;
            use warning;
            my %myhash = (say => "Hello", to => "Stack Overflow");
            sub hello {
             my ($say, $to) = @_;
             $say =  $say ? $say : $myhash{say};
             $to =  $to ? $to : $myhash{to};
             print "$say $to\n";
            }
            hello('Perl');      # output :Perl Stack Overflow
            hello('','SO');     # output :Hello SO
            hello('Perl','SO'); # output :Perl SO
            hello();            # output :Hello Stack Overflow
          

          如需更详细和完整的示例,请参阅 Perl Best Practices

          【讨论】:

            【解决方案6】:

            我最喜欢这种方式:从 Perl 5.10 开始,您可以使用 // 检查变量是否已定义,并在未定义时提供替代值。 所以,一个简单的例子是:

            我的 $DEFAULT_VALUE = 42;

            sub f {
                my ($p1, $p2) = @_;
                $p1 //= 'DEFAULT';
                $p2 // = $DEFAULT_VALUE;
            }
            

            另一种选择是使用shift 指令从@_ 获取参数:

            sub f {
                my $p1 = shift // 'DEFAULT';
            }
            

            来源:https://perlmaven.com/how-to-set-default-values-in-perl

            【讨论】:

              【解决方案7】:

              CPAN 上有 Attribute::Default 模块。可能比这更干净,并且避免了一些复杂性(例如,如果您想将 false 传递给您的子例程怎么办?)。

              我也看到人们使用my $var = exists @_[0] ? shift : "Default_Value";,但 Perl 的文档指出 calling exists on arrays is deprecated,所以我不会真的推荐它。

              来自文档页面的Attribute::Default 的片段:

                sub vitals : Default({age => 14, sex => 'male'}) {
                   my %vitals = @_;
                   print "I'm $vitals{'sex'}, $vitals{'age'} years old, and am from $vitals{'location'}\n";
                }
              
                 # Prints "I'm male, 14 years old, and am from Schenectady"
                 vitals(location => 'Schenectady');
              

              【讨论】:

                【解决方案8】:

                其他答案中已经讨论了解决问题的最佳方法。
                不过让我印象深刻的一件事是,您说:

                sub hello {
                   print @_ || "Hello world";
                }
                

                如果您只需要一个参数,这很好用。

                您是否真的尝试过该代码?它将打印参数的数量,如果没有提供,则打印Hello World!
                这样做的原因是 || 运算符优先并在标量上下文中强制左侧,从而将 @_ 减少到您提供的参数数量,而不是参数本身!
                查看perlop 了解有关 Perl 中运算符的更多信息。

                HTH,
                保罗

                【讨论】:

                  【解决方案9】:

                  更多糖,另见Method::Signatures

                  func add($this = 23, $that = 42) {
                      return $this + $that;
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-08-01
                    • 2018-04-01
                    • 2012-08-06
                    • 2011-03-25
                    • 2018-06-20
                    • 1970-01-01
                    • 2012-05-04
                    相关资源
                    最近更新 更多