Perl OO 包中简化的默认参数处理

发布于 2024-12-07 20:11:29 字数 941 浏览 0 评论 0原文

这是我所拥有的重要子集:

sub logger {
    my $self = shift;
    my %def =  (
        type => $self->{options}{name}, 
        severity => 1,
        date => $self->now(),
        message => ''  
    );
    my %opt = %def;
    if ( my $ref = shift ) {
        %opt = (%def, %{$ref});
    }
    croak('message is a required option') if $opt{message} eq '';
    warn($opt{type} . ': ' . $opt{message} . "\n") if ( $self->{_verbose} );
    # Do some other interesting things.
}

那么我可以这样调用它:

$op->logger({message => 'Some message'});

因此,如果我的任何参数丢失,它们将获得我在 %def 哈希中指定的默认值。如果缺少必需的参数,我就会死。

它的基础是我用用户指定的内容重载 def 哈希。

    if ( my $ref = shift ) {
        %opt = (%def, %{$ref});
    }

问题是他们可以指定我的选项列表之外的内容,或者发送散列而不是散列引用,或者标量,或者 undef,或者许多其他可能导致崩溃的方式。

我确信有一种更优雅的方法来处理这个问题。
我似乎记得一些使用 ref() 的代码,如果没有传入任何内容,则不会崩溃。

Here is the important subset of what I have:

sub logger {
    my $self = shift;
    my %def =  (
        type => $self->{options}{name}, 
        severity => 1,
        date => $self->now(),
        message => ''  
    );
    my %opt = %def;
    if ( my $ref = shift ) {
        %opt = (%def, %{$ref});
    }
    croak('message is a required option') if $opt{message} eq '';
    warn($opt{type} . ': ' . $opt{message} . "\n") if ( $self->{_verbose} );
    # Do some other interesting things.
}

So then I can call it like so:

$op->logger({message => 'Some message'});

So if any of my parameters are missing, they get the defaults I've specified in the %def hash. If a required parameter is missing, I die.

The basis of it is I overload the def hash with what the user specified with this.

    if ( my $ref = shift ) {
        %opt = (%def, %{$ref});
    }

Problem with this is they could specify things outside my list of options, or send in a hash instead of a hash ref, or a scalar, or undef, or many other ways this could blow up.

I'm sure there is a more elegant way to handle this.
I seem to recall some code using ref() that didn't blow up if nothing was passed in.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦旅人picnic 2024-12-14 20:11:29

Method::Signatures 正是您所寻找的for and 非常优雅:

method logger (
    :$type     = $self->{options}{name},
    :$severity = 1,
    :$date     = $self->now,
    :$message! # No default and required, so croaks if not provided by caller.
) {
    my %opt = (
        type     => $type, 
        severity => $severity,
        date     => $date,
        message  => $message
    );
    # Do some other interesting things.
}

签名中的冒号指定命名参数(作为哈希传递)。 $message 后面的感叹号使其成为必需。

Method::Signatures does precisely what you're looking for and is so very elegant :

method logger (
    :$type     = $self->{options}{name},
    :$severity = 1,
    :$date     = $self->now,
    :$message! # No default and required, so croaks if not provided by caller.
) {
    my %opt = (
        type     => $type, 
        severity => $severity,
        date     => $date,
        message  => $message
    );
    # Do some other interesting things.
}

The colons in the signature designate named parameters (passed as a hash). The exclamation mark following $message makes it required.

谁把谁当真 2024-12-14 20:11:29

处理这个问题的优雅方式都可以方便地捆绑在 Moose 中,如果 Moose 对你来说太重的话,甚至可以使用 Mouse 或 Moo。

The elegant way of handling this is all conveniently bundled for you in Moose, or even Mouse or Moo if Moose is too heavy for you.

兮子 2024-12-14 20:11:29

我想我会做类似的事情。毫无疑问,尽管有大量 CPAN 模块可以使这一切变得更简单。

sub logger {
    my $self = shift;

    # Set $ref to an empty hash ref if it's not given.
    # This makes a lot of later code far simpler
    my $ref = shift || {};

    # Check you have a hash ref
    unless (ref $ref eq 'HASH') {
        die "Argument to logger must be a hash ref";
    }

    my %def =  (
        type => $self->{options}{name}, 
        severity => 1,
        date => $self->now(),
        message => '',
    );


    my %opt = (%def, %$ref);

    # Now check we only have valid options. Assume that all valid
    # keys are in %def
    foreach (keys %opt) {
        delete $opt{$_} unless exists $def{$_};
    }

    croak('message is a required option') if $opt{message} eq '';
    warn($opt{type} . ': ' . $opt{message} . "\n") if ( $self->{_verbose} );
    # Do some other interesting things.
}

I think I'd do something like that. Although there are, no doubt, plenty of CPAN modules that make this simpler.

sub logger {
    my $self = shift;

    # Set $ref to an empty hash ref if it's not given.
    # This makes a lot of later code far simpler
    my $ref = shift || {};

    # Check you have a hash ref
    unless (ref $ref eq 'HASH') {
        die "Argument to logger must be a hash ref";
    }

    my %def =  (
        type => $self->{options}{name}, 
        severity => 1,
        date => $self->now(),
        message => '',
    );


    my %opt = (%def, %$ref);

    # Now check we only have valid options. Assume that all valid
    # keys are in %def
    foreach (keys %opt) {
        delete $opt{$_} unless exists $def{$_};
    }

    croak('message is a required option') if $opt{message} eq '';
    warn($opt{type} . ': ' . $opt{message} . "\n") if ( $self->{_verbose} );
    # Do some other interesting things.
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文