qod*_*nja 6 oop perl inheritance constants moose
所以我开始关注我的Moosey业务,我认为在我使用数字的地方使用常数可能会很好,以便明确这些数字的含义或以后更改
所以在父类中我添加了标准的'use constant'
package Parent;
use constant {
NO_LEVEL => 0,
MY_LEVEL => 1,
YOUR_LEVEL => 2,
};
package Child;
extends 'Parent';
#just to demonstrate that child can or cannot access the constant
sub printMyLevel{
print MY_LEVEL;
}
Run Code Online (Sandbox Code Playgroud)
但是子类不知道父级中设置的常量!卫生署!
我猜我必须做一些Moose魔法才能让它正常工作,或完全不同.我在这个问题上的搜索没有拉出任何结果= /
Sin*_*nür 11
常量是子程序.
{
package Parent;
use Moose;
use namespace::autoclean;
use constant {
NO_LEVEL => 0,
MY_LEVEL => 1,
YOUR_LEVEL => 2,
};
__PACKAGE__->meta->make_immutable;
};
{
package Child;
use Moose;
use namespace::autoclean;
extends 'Parent';
sub printMyLevel {
my $self = shift;
my $class = ref $self;
print $class->MY_LEVEL;
}
__PACKAGE__->meta->make_immutable;
}
package main;
my $child = Child->new;
$child->printMyLevel;
Run Code Online (Sandbox Code Playgroud)
请记住,常量是具有空原型的子例程.perl在编译期间利用它来内联它们.但是,方法调用忽略了原型,因此不会内联以这种方式访问的可继承常量.
由于常量是子例程,并且您可以通过调用它们来获得继承,因为方法位已经被覆盖得很死,所以这里有一个不同的旋转。
如果您知道您只在单个文件中工作,则可以使用词法常量来桥接包:
package Parent;
our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL);
*NO_LEVEL = \0; # this split declaration installs aliases to numbers
*MY_LEVEL = \1; # into the lexicals. since numbers are constants
*YOUR_LEVEL = \2; # to perl, the aliased names are also constants
package Child;
# just to demonstrate that anything below can access the constants
sub printAll {
print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n";
}
Child->printAll; # 0 1 2
eval {$NO_LEVEL = 3} or print "error: $@\n";
# error: Modification of a read-only value attempted at ...
Run Code Online (Sandbox Code Playgroud)
如果在分配给常量时不需要 perl 死掉,则our声明会变得更简单(并且可以是 a my):
our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2);
Run Code Online (Sandbox Code Playgroud)
您可以恢复不变的本质,同时仍然使用简洁的语法和一点魔法:
my $constant = sub {Internals::SvREADONLY($_[$_], 1) for 0 .. $#_};
package Parent;
$constant->(our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2));
package Child;
# just to demonstrate that anything below can access the constants
sub printAll {
print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n"; # interpolates :)
}
Child->printAll; # 0 1 2
eval {$NO_LEVEL = 3} or print "error: $@\n";
# error: Modification of a read-only value attempted at ...
Run Code Online (Sandbox Code Playgroud)
您当然可以省略$constantcoderef 并内联魔法:
package Parent;
Internals::SvREADONLY($_, 1)
for our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2);
Run Code Online (Sandbox Code Playgroud)