是否可以使用 Perl 的 Moose/MooseX::Declare 自动强制传递给委托方法的参数(来自 Array 特征)?

发布于 2024-09-28 07:27:15 字数 1183 浏览 1 评论 0原文

我正在创建一个类,其中包含 IP 地址列表,作为 Net::IP 对象。

我已将 Net::IP 对象包装为子类型 (IPAddress),并定义了从字符串到 IPAddress 的强制转换。然后,我向名为 ip_list 的类添加了一个属性,其类型为 ArrayRef[IPAddress],并委托给 Array 特征的 push 方法。

use MooseX::Declare;
use Moose::Util::TypeConstraints;

use Net::IP;

subtype 'IPAddress'
    => as 'Object'
    => where { $_->isa('Net::IP') };

coerce 'IPAddress'
    => from 'Str'
    => via { Net::IP->new( $_ ) };

class IPs {

    has 'ip_list' => ( traits  => ['Array'],
                       isa    => 'ArrayRef[IPAddress]',
                       is     => 'rw',
                       coerce => 1,
                       auto_deref => 1,
                       default => sub { [] },
                       handles => {
                           add_ip    => 'push'
                       }
                       );

}

但是,如果我尝试像这样调用委托方法:

my $o = IPs->new();
$o->add_ip( '192.168.0.1' );

我收到错误“值 SCALAR(0x8017e8) 没有通过容器类型约束‘IPAddress’…”

所以显然 add_ip 的参数没有被强制。

是否可以做我正在尝试的事情,或者我应该手动完成这一切?我已经翻遍了 Moose 手册,但没有看到任何表明这两种情况的内容,但我可能遗漏了一些东西。

I'm creating a class which will contain a list of IP addresses, as Net::IP objects.

I've wrapped the Net::IP object as a subtype (IPAddress), and defined a coercion from a string to IPAddress. Then I've added an attribute to the class called ip_list with the type ArrayRef[IPAddress], and delegated to the push method of the Array trait.

use MooseX::Declare;
use Moose::Util::TypeConstraints;

use Net::IP;

subtype 'IPAddress'
    => as 'Object'
    => where { $_->isa('Net::IP') };

coerce 'IPAddress'
    => from 'Str'
    => via { Net::IP->new( $_ ) };

class IPs {

    has 'ip_list' => ( traits  => ['Array'],
                       isa    => 'ArrayRef[IPAddress]',
                       is     => 'rw',
                       coerce => 1,
                       auto_deref => 1,
                       default => sub { [] },
                       handles => {
                           add_ip    => 'push'
                       }
                       );

}

However if I try to call the delegated method like so:

my $o = IPs->new();
$o->add_ip( '192.168.0.1' );

I get the error "Value SCALAR(0x8017e8) did not pass container type constraint 'IPAddress' at ..."

So obviously the parameter to add_ip is not being coerced.

Is it possible to do what I'm attempting, or should I just do all this manually? I've trawled through the Moose manuals but I've not seen anything that would indicate either way, but I am probably missing something.

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

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

发布评论

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

评论(1

初见终念 2024-10-05 07:27:15

不幸的是,Moose 不会链接强制转换(在内部解析这些强制转换并以自动方式找出“正确的事情”是什么会非常复杂),因此您需要自己定义该链:

use Net::IP;

class_type 'Net::IP';

coerce 'Net::IP'
    => from 'Str'
    => via { Net::IP->new( $_ ) };

subtype 'ArrayRefOfIPAddresses'
    => as 'ArrayRef[Net::IP]';

coerce 'ArrayRefOfIPAddresses'
    => from 'ArrayRef[Str]'
    => via { [ map { Net::IP->new($_) } @$_ ] };

coerce 'ArrayRefOfIPAddresses'
    => from 'Str'
    => via { [ Net::IP->new($_) ] };

coerce 'ArrayRefOfIPAddresses'
    => from 'Net::IP'
    => via { [ $_ ] };

class IPs {

    has 'ip_list' => ( traits  => ['Array'],
                       isa    => 'ArrayRefOfIPAddresses',
                       # ... rest of declaration as before
                     );

}

附言。由于您使用的是 Array 本机委托特征,我建议您避免使用 auto_deref - 添加一个处理程序:

has ip_list => (
    is => 'bare',
    # ...
    handles => {
        # ...
        ip_list => 'elements',
    },
);

Unfortunately Moose does not chain coercions (it would be really complicated to parse these internally and figure out what the "right thing to do" is in an automatic fashion), so you need to define the chain yourself:

use Net::IP;

class_type 'Net::IP';

coerce 'Net::IP'
    => from 'Str'
    => via { Net::IP->new( $_ ) };

subtype 'ArrayRefOfIPAddresses'
    => as 'ArrayRef[Net::IP]';

coerce 'ArrayRefOfIPAddresses'
    => from 'ArrayRef[Str]'
    => via { [ map { Net::IP->new($_) } @$_ ] };

coerce 'ArrayRefOfIPAddresses'
    => from 'Str'
    => via { [ Net::IP->new($_) ] };

coerce 'ArrayRefOfIPAddresses'
    => from 'Net::IP'
    => via { [ $_ ] };

class IPs {

    has 'ip_list' => ( traits  => ['Array'],
                       isa    => 'ArrayRefOfIPAddresses',
                       # ... rest of declaration as before
                     );

}

PS. since you are using the Array native delegation trait, I would recommend you avoid auto_deref - add a handler instead:

has ip_list => (
    is => 'bare',
    # ...
    handles => {
        # ...
        ip_list => 'elements',
    },
);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文