我发现自己反复编写和重写以下类型的代码:
my %default = (x => "a", y => "b");
sub new
{
my ($package, $config) = @_;
my $self = {%default};
for my $k (keys %default) {
$self->{$k} = $config->{$k} if defined $config->{$k};
}
for my $k (keys %$config) {
if (! exists $default{$k}) {
carp "Unknown config option $k\n";
}
}
bless $self;
# etc. etc.
}
在我制作自己的模块之前,我只是想知道CPAN上是否还有这样的东西?我只想要这个非常简单的上述功能,所以建议使用Moose不是这个问题的合适答案。
答案 0 :(得分:11)
Moose支持属性的默认值,例如:
has 'foo' => ( is => 'rw', isa => 'Int', default => 42 );
但如果你不想沿着穆斯路线走下去,那么实现你想要的更简单的方法是:
sub new {
my ( $package, %config ) = @_;
my %defaults = ( x => 'a', y => 'b' );
my $self = { %defaults, %config };
# error checking here
return bless $self, $package;
}
由于在哈希初始化中两次指定相同的哈希键会破坏第一个哈希,因此%config
中的任何键都将覆盖%defaults
中的任何键。
答案 1 :(得分:4)
Params::Validate可能会有所帮助。它允许您删除%defaults
哈希并为每个(可能是可选的)参数指定默认值。
此外,您可以使用map
使其更简洁一些。当然,这会默默地忽略无效的参数。
#!/usr/bin/perl
package My::Class;
use strict; use warnings;
my %defaults = ( x => 'a', y => 'b' );
sub new {
my $class = shift;
my ($args) = @_;
my $self = {
%defaults,
map {
exists $args->{$_} ? ($_ => $args->{$_}) : ()
} keys %defaults,
};
return bless $self, $class;
}
package main;
use strict; use warnings;
my $x = My::Class->new({ x => 1, z => 10});
use YAML;
print Dump $x;
输出:
--- !!perl/hash:My::Class x: 1 y: b
答案 2 :(得分:3)
如果您已在模块中使用Moose,则可以通过合并MooseX::Getopt和MooseX::SimpleConfig来获得此行为。您的配置文件可以包含默认值,然后根据需要通过将这些值传递给构造函数来覆盖任何内容:
my $obj = Class->new_with_options(configfile => "myconfig.yaml", key1 => 'val', key2 => 'val');
package Class;
use Moose;
with 'MooseX::Getopt::Strict',
'MooseX::SimpleConfig';
has configfile => (
is => 'ro', isa => 'Str',
traits => ['Getopt'],
documentation => 'File containing default configs',
lazy => 1,
default => sub { File::Spec->catfile($base_dir, 'my_default_config.yaml') },
);
has [ qw(key1 key2) ] => (
is => 'ro', isa => 'Str',
);