如何为可选子例程参数指定默认值?

时间:2015-04-11 10:57:08

标签: perl

是否有一种优雅的方法来指定子程序参数的默认值?

目前,我使用以下方法:

use strict;
use warnings;

func1( "arg1", "arg2", opt1 => "first option", opt2 => 0 );

sub func1 {
    my ( $arg1, $arg2, %opt ) = @_;

    $opt{opt1} //= "no option";
    $opt{opt2} //= 1;
    $opt{opt3} //= [];
}
当有很多选择时,它看起来有点难看。我宁愿做

sub func2 {
    my ( $arg1, $arg2, $opt ) = process_args( 
        opt1 => "no option", opt2 => 1, opt3 => []
    );
}

我能想出的最好的方法是:

sub func2 {
    my ( $arg1, $arg2, $opt ) = process_args(
        \@_, 2, opt1 => "no option", opt2 => 1, opt3 => []
    );
}

sub process_args {
    my ($a, $n, %opt_info ) = @_;

    my @b = splice @$a, 0, $n;
    my %opt = @$a;
    for my $key (keys %opt_info) {
        $opt{$key} //= $opt_info{$key};
    }
    return (@b, \%opt);
}

但现在我遇到了另一个问题,我必须将\@_和非选项参数的数量(此处为2)传递给process_args ..

3 个答案:

答案 0 :(得分:6)

sub func1 {
    my $arg1 = shift;
    my $arg2 = shift;
    my %opt = (
       opt1 => 'default',
       opt2 => 'default',
       @_
    );

或者,您可以使用Params::Validate

答案 1 :(得分:3)

我不记得看到一个明确写的子程序来处理子程序参数。你有Ruby背景吗?

您可以通过默认列表定义选项哈希,然后在@_中传递任何内容。喜欢这个

use strict;
use warnings;

func1( "arg1", "arg2", opt1 => "first option", opt2 => 0 );

sub func1 {
  my ( $arg1, $arg2 ) = splice @_, 0, 2;
  my %opts = (
    opt1 => "no option",
    opt2 => 1,
    opt3 => [],
    @_,
  );
}

另一种机制,如果你想对不支持的参数进行警告,就是要做很多事情,但是使用delete,并确保之后哈希是空的,就像这样

use strict;
use warnings;

use Data::Dump;
use Carp 'croak';

func1( "arg1", "arg2", opt9 => 9 );

sub func1 {
  my ( $arg1, $arg2, %opt ) = @_;

  my $opt1 = delete $opt{opt1} // 'no option';
  my $opt2 = delete $opt{opt2} // 1;
  my $opt3 = delete $opt{opt3} // [];

  croak "Unexpected parameters: ", join ',', keys %opt if keys %opt;
}

<强>输出

Unexpected parameters: opt9 at E:\Perl\source\args.pl line 16.
  main::func1("arg1", "arg2", "opt9", 9) called at E:\Perl\source\args.pl line 7

答案 2 :(得分:1)

尝试:

# isolate the default options
{
  my %default_options = (
    opt1 => 'default for opt1',
    opt2 => 'default for opt2',
  );

  sub func1 {
    my $arg1 = shift @_;
    my $arg2 = shift @_;

    # set options
    my %opt  = %default_options;
    if( my %given_opts = @_ ){
      for my $key ( keys %opt ){
        if( exists $given_opts{$key} ){
          $opt{$key} = $given_opts{$key};
        }
      }
    }

    # rest of func1
  }
}