我对Perl有点新鲜。我正在尝试以下列方式定义/使用类:
package A::B::C;
use strict;
use warnings;
use Moose;
use aliased 'A::B::D';
has 'attribute' => (isa => 'ArrayRef[D]', is => 'ro', required => 1);
创建对象时:
use aliased 'A::B::C';
use aliased 'A::B::D';
my $aref = [D->new()];
C->new($aref);
然而,当Moose抱怨时,这失败了:
Attribute (attribute) does not pass the type constraint because: Validation failed for 'ArrayRef[D]' with value ARRAY(0x7f2b658b51c0)
但是,如果我切换到不使用别名,它可以工作(当然应该这样):
package A::B::C;
use strict;
use warnings;
use Moose;
use A::B::D;
has 'attribute' => (isa => 'ArrayRef[A::B::D]', is => 'ro', required => 1);
我的问题是为什么使用别名位不适用于Moose?
由于
答案 0 :(得分:1)
穆斯不知道use aliased
。 pragma use aliased
是Perl之上的hack;它所做的只是创建一个带有短名称的子程序,该子程序返回类名。所以
use aliased 'A::B::D';
相当于
use A::B::D;
sub D() { 'A::B::D' }
然后,当你说D->new()
之类的东西时,Perl注意到有一个名为D
的子程序(常量),并将D
解释为子程序调用,然后调用该方法结果。 (而不是像通常那样将D
解释为字符串常量)。即使是Perl,D
也不是包名;只是像包名一样的东西!
此外,Moose有自己的解析类型声明的系统(这就是为什么你可以像你一样将它们作为字符串给出)以及它自己的全局类型声明概念。这些都不知道aliased
,因此Moose正在使用其默认行为将未识别的类型视为(全局)包名称。
如果您了解aliased
的工作原理,可以通过
has 'attribute' => (isa => 'ArrayRef['.D.']', is => 'ro', required => 1);
但最好记住
Type names are global throughout the current Perl interpreter
并在任何地方使用完全限定的包名称,或者使用Type::Tiny并写入
package A::B::C;
use Moose;
use aliased 'A::B::D';
use Types::Standard qw/ ArrayRef /;
use Type::Utils qw( class_type );
has 'attribute' => (isa => ArrayRef[class_type D], is => 'ro', required => 1);
(请注意D
周围缺少引号,仅可能因use aliased
而感谢!)。
(Type::Tiny
可能比Moose类型更快,所以你可能还是想考虑它。)