在将对象推送到我的 perl Moo class 中的 ArrayOf[] 成员时,如何检查对象是否有效?
How do I check if an object is valid when pushed to an ArrayOf[] member in my perl Moo class?
我创建了一个包含对象数组的 Moo class,使用 Types::Standard 对类型进行检查,我想验证我是否将正确的对象放入该数组中而不用硬-编码太多。这是我现在拥有的示例:
package MyClass;
use Moo;
use Types::Standard qw( ArrayRef InstanceOf );
# Initially empty array of objects
has connected => (
is => 'ro',
isa => ArrayRef[InstanceOf['MyClass']],
default => sub { [] }
);
# Add an object to our internal list
sub connect {
my ( $self, $other ) = @_;
# TODO: Check if "$other" is actually an InstanceOf['MyClass']
# without doing "$self->connected( $self->connected )"
push @{$self->connected}, $other;
}
在 connect() 中,我将对象添加到我的内部数组,但如果我理解正确,则永远不会根据 InstanceOf['MyClass']
检查对象,因为我实际上 再次设置数组引用
对每个 new 对象执行此验证的好方法是什么?在推送一个新项目后,我曾短暂地考虑过做 $self->connected( $self->connected )
,但是那将必须验证 每个 对象。
理想情况下,我什至不想知道 ArrayRef 中到底有什么,只知道它是必须检查的东西。我查看了 Type::Tiny 文档中的 _type_parameter_,但我不太清楚如何在我的代码中使用它。
这个答案忽略了 Moo,因为你可以在不使用它的情况下实现你所要求的。如果您愿意,这不会阻止您使用它,但不需要它来执行您的要求。
Perl 本身是有效的 duck 类型,但 确实 支持 bless 将哈希引用加持到 class,允许您将方法附加到它。
就像在任何面向对象的系统中一样,classes 可以在 perl 中相互继承,你可以说任何 class isa 另一个class。然后你的代码可以简单地检查它是否已经传递了一个像 class.
这样幸运的哈希引用
因此,如果我正确理解您的问题,您可以通过确保您的 class 层次结构规定正确的方式来确保只将相关类型(适当祝福)的 classes 添加到您的数组中isa 关系并检查它。
因此,如果您定义的基类型是您要检查的类型,您可以让所有其他类型声明它们是:
您的基础中可能的示例声明:
package MyCore;
sub new
{
my ($Class, $obj);
$Class=shift;
$obj= { Key => 'Value' };
bless($obj, $Class);
return($obj);
}
派生类型中可能的声明:
use MyCore;
package MyDerived;
@MyDerived::ISA=('MyCore');
sub new()
{
my ($Class, $Obj);
$Class=shift;
$Obj=MyCore::new();
$Obj->{NewKey}='NewValue';
bless($Obj, $Class);
}
然后当你添加到数组时:
sub connect()
{
my ($Self, $Other);
$Self=shift;
$Other=($#_>=0)?shift:undef;
if(defined($Other) && $Other->isa('MyCore'))
{
push(@{$Self->{Connected}}, $Other);
}
}
我们在基于 mod_perl 构建的大容量网络服务器中使用这种方法,对于其他面向对象环境的用户来说,它简单易懂。
这执行相同的检查:
use Type::Tiny::Class qw( );
my $MyClass_type = Type::Tiny::Class->new( class => 'MyClass' );
sub connect {
my ( $self, $other ) = @_;
$MyClass_type->check($other)
or die "Validation error";
push @{ $self->connected }, $other;
}
看来你也可以用
if ( my $error = $MyClass_type->validate($other, '$other') ) {
die($error);
}
和
if ( my $errors = $MyClass_type->validate_explain($other, '$other') ) {
die(join("\n", @$errors));
}
->validate
可能是最好的选择。
未测试。
旧问题的答案,因为我已经有一段时间无法登录 StackExchange...
package MyClass;
use Moo;
use Types::Standard qw( ArrayRef InstanceOf );
use Sub::HandlesVia;
has connected => (
is => 'ro',
isa => ArrayRef[InstanceOf['MyClass']],
default => sub { [] },
handles_via => 'Array',
handles => {
'connect' => 'push',
}
);
Sub::HandlesVia 会自动为您进行类型检查。
我创建了一个包含对象数组的 Moo class,使用 Types::Standard 对类型进行检查,我想验证我是否将正确的对象放入该数组中而不用硬-编码太多。这是我现在拥有的示例:
package MyClass;
use Moo;
use Types::Standard qw( ArrayRef InstanceOf );
# Initially empty array of objects
has connected => (
is => 'ro',
isa => ArrayRef[InstanceOf['MyClass']],
default => sub { [] }
);
# Add an object to our internal list
sub connect {
my ( $self, $other ) = @_;
# TODO: Check if "$other" is actually an InstanceOf['MyClass']
# without doing "$self->connected( $self->connected )"
push @{$self->connected}, $other;
}
在 connect() 中,我将对象添加到我的内部数组,但如果我理解正确,则永远不会根据 InstanceOf['MyClass']
检查对象,因为我实际上 再次设置数组引用
对每个 new 对象执行此验证的好方法是什么?在推送一个新项目后,我曾短暂地考虑过做 $self->connected( $self->connected )
,但是那将必须验证 每个 对象。
理想情况下,我什至不想知道 ArrayRef 中到底有什么,只知道它是必须检查的东西。我查看了 Type::Tiny 文档中的 _type_parameter_,但我不太清楚如何在我的代码中使用它。
这个答案忽略了 Moo,因为你可以在不使用它的情况下实现你所要求的。如果您愿意,这不会阻止您使用它,但不需要它来执行您的要求。
Perl 本身是有效的 duck 类型,但 确实 支持 bless 将哈希引用加持到 class,允许您将方法附加到它。
就像在任何面向对象的系统中一样,classes 可以在 perl 中相互继承,你可以说任何 class isa 另一个class。然后你的代码可以简单地检查它是否已经传递了一个像 class.
这样幸运的哈希引用因此,如果我正确理解您的问题,您可以通过确保您的 class 层次结构规定正确的方式来确保只将相关类型(适当祝福)的 classes 添加到您的数组中isa 关系并检查它。
因此,如果您定义的基类型是您要检查的类型,您可以让所有其他类型声明它们是:
您的基础中可能的示例声明:
package MyCore;
sub new
{
my ($Class, $obj);
$Class=shift;
$obj= { Key => 'Value' };
bless($obj, $Class);
return($obj);
}
派生类型中可能的声明:
use MyCore;
package MyDerived;
@MyDerived::ISA=('MyCore');
sub new()
{
my ($Class, $Obj);
$Class=shift;
$Obj=MyCore::new();
$Obj->{NewKey}='NewValue';
bless($Obj, $Class);
}
然后当你添加到数组时:
sub connect()
{
my ($Self, $Other);
$Self=shift;
$Other=($#_>=0)?shift:undef;
if(defined($Other) && $Other->isa('MyCore'))
{
push(@{$Self->{Connected}}, $Other);
}
}
我们在基于 mod_perl 构建的大容量网络服务器中使用这种方法,对于其他面向对象环境的用户来说,它简单易懂。
这执行相同的检查:
use Type::Tiny::Class qw( );
my $MyClass_type = Type::Tiny::Class->new( class => 'MyClass' );
sub connect {
my ( $self, $other ) = @_;
$MyClass_type->check($other)
or die "Validation error";
push @{ $self->connected }, $other;
}
看来你也可以用
if ( my $error = $MyClass_type->validate($other, '$other') ) {
die($error);
}
和
if ( my $errors = $MyClass_type->validate_explain($other, '$other') ) {
die(join("\n", @$errors));
}
->validate
可能是最好的选择。
未测试。
旧问题的答案,因为我已经有一段时间无法登录 StackExchange...
package MyClass;
use Moo;
use Types::Standard qw( ArrayRef InstanceOf );
use Sub::HandlesVia;
has connected => (
is => 'ro',
isa => ArrayRef[InstanceOf['MyClass']],
default => sub { [] },
handles_via => 'Array',
handles => {
'connect' => 'push',
}
);
Sub::HandlesVia 会自动为您进行类型检查。