在声明类时,使用Moose别名似乎不起作用

时间:2017-07-11 13:52:15

标签: perl perl-module moose

我对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?

由于

1 个答案:

答案 0 :(得分:1)

穆斯不知道use aliased。 pragma use aliased是Perl之上的hack;它所做的只是创建一个带有短名称的子程序,该子程序返回类名。所以

use aliased 'A::B::D';

相当于

use A::B::D;

sub D() { 'A::B::D' }

(见aliased.pm#L45

然后,当你说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类型更快,所以你可能还是想考虑它。)