【问题标题】:Conditional parameter passing with MooseX::Params::Validate使用 MooseX::Params::Validate 传递条件参数
【发布时间】:2016-09-25 04:13:15
【问题描述】:

我经常使用 Perl 中的 Moose 包,这些包使用 MooseX::Params::Validate 来定义接口。这些接口往往相当灵活,并允许多个可选参数。不幸的是,这是 Perl,因此返回类型将根据可选参数而有所不同,并且在大多数情况下,当在调用者中定义时传递可选参数是有好处的。此代码库中使用了从MooseX::Params::Validate 导出的各种方法,因此由于处理包的各种方式undef 参数我无法传递它无论如何都会很优雅。我倾向于使用以下方法,但它在评论中出现了很多,我想问是否有另一种方法可以实现这种灵活性。

use strict;
use warnings;

my $bar;

Foo->foo({
    foo => 'I, Foo need a VERY flexible interface. ',
    $bar ? ( bar => $bar ) : ()
});

$bar = "Very flexible...";

Foo->foo({
    foo => 'I, Foo need a VERY flexible interface. ',
    $bar ? ( bar => $bar ) : ()
});

package Foo;

use Moose;
use MooseX::Params::Validate;

sub foo {
    my $self = shift;
    my ( $foo, $bar ) = validated_list(
      \@_,
      foo => { isa => 'Str' },
      bar => { isa => 'Str', optional => 1 },
    );

    print $foo . $bar . "\n";
}

1;

检查变量defined 状态的三元运算符总是让我想要一个// 类型参数选项,但我看不到任何支持这种类型操作的地方。

caller 的答案是首选,因为我不想(不会)更改各种包的接口,但我愿意接受显示处理 undef 传递的参数值的方法的答案.

【问题讨论】:

  • 对于调用者来说,你的“成语”似乎很费力[更重要的是,容易出错]。用更直接的辅助函数替换三进制怎么样:sub defme { my(@arr); push(@arr,$_[0],$_[1]) if ($_[1]); @arr; }?然后,你有defme("bar",$bar) 而不是三元。或者,在构造函数中,根据需要调用validated_list 之前执行////=,因为第一个参数始终指向一个临时值?
  • @CraigEstey 你能解释一下它是如何更容易出错和费力的(我主要关心的是可读性),以及你的解决方案是如何工作的,因为我没有看到它是如何适用的?
  • 我的函数,AFAICT,做三元组所做的事情——产生一个填充有($sym,$val) 或空的数组。而且,IMO,defme("bar",$bar) 比 [longer] $bar ? (bar => $bar) : () 更具可读性。 fnc 调用比三元语法更短更简单。并且,如果需要,您可以将调试 printfs 添加到 fnc。但是,最好让所有调用者只做(bar => $var) 并让foo 处理它,而不是把责任放在调用者身上。即使您仍然想要三元,foo 仍然需要防御性地检查这一点。那么,如果检查为什么不修复呢?
  • 如果 $bar 是 undef,如果它得到 bar => $bar,它看起来像 foo 中断。但是,正如我所说,让每个调用者都进行检查(通过三元)?我只是通过任何东西并让foo 从哈希中删除 undef 值:@sym = keys(%$hash); for $sym (@sym) { delete{$hash->{$sym}} unless (defined($hash->{$sym})); }

标签: perl moose


【解决方案1】:

正如Craig Estey 在他的评论中所说,我认为将选项传递给您的函数是有意义的,而不必关心它们是否未定义。相反,在调用MooseX::Params::Validate::validated_list() 之前,将未定义的哈希键作为预处理步骤。例如:

use strict;
use warnings;

my $bar;

Foo->foo({
    foo => 'I, Foo need a VERY flexible interface. ',
    bar => $bar
});

package Foo;

use Moose;
use MooseX::Params::Validate ();

sub foo {
    my $self = shift;

    my ( $foo, $bar ) = validated_list(
      \@_,
      foo => { isa => 'Str' },
      bar => { isa => 'Str', optional => 1 },
    );

    $bar //= 'undef';  # Just to avoid printing warning: Use of uninitialized value 
    print $foo . $bar . "\n";
}

sub validated_list {
    for (keys %{ $_[0]->[0] } ) {
        delete $_[0]->[0]{$_} if !defined $_[0]->[0]{$_};
    }
    return MooseX::Params::Validate::validated_list( @_ );
}
1;

【讨论】:

  • Moose 包对我的问题来说是一个黑盒子
  • @MattSizzle 我不确定您所说的black box 是什么意思。对我来说,black box 意味着你不能修改里面的任何东西。您只能通过 API 进行通信。你能解释一下你的想法吗?
【解决方案2】:

Maybe 类型可能是您正在寻找的。通常 MooseX::Params::Validate not 允许将 undef 传递给像 Str 这样的东西,迫使你使用三元来有条件地通过或不通过它。一个可选变量在子例程中无论如何都是 undef,但是使用 Maybe 它可以让调用者更容易地传递他们拥有的变量(可能会或未定义)。

sub foo {
    my $self = shift;
    my ( $foo, $bar ) = validated_list(
      \@_,
      foo => { isa => 'Str' },
      bar => { isa => 'Maybe[Str]', optional => 1 }
    );

    print $foo . $bar . "\n";
}

通过使用 Maybe[Str],它现在将接受 undef 值,您可以按照您认为适合您的子例程的方式处理这个 undef。

Maybe[`a] accepts either `a or undef.

http://search.cpan.org/dist/Moose-2.0604/lib/Moose/Manual/Types.pod

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-09
    • 2013-07-18
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 2011-03-20
    • 1970-01-01
    相关资源
    最近更新 更多