编写属性特征
Writing an attribute trait
我要为新项目选择使用什么语言:Perl5 或 Perl6。到目前为止,除了缺少 Moo
的懒惰属性外,6 次获胜。我在模块中发现的两个实现缺少关键功能。因此,我尝试编写自己的实现。
角色与 Class
我遇到的第一个问题是角色中声明的 .package
属性的内容。考虑以下内容:
role HOW1 {
method compose ( Mu $class ) {
note "HOW1.compose";
nextsame;
}
}
role HOW2 {
method compose ( Mu $class ) {
note "HOW2.compose";
nextsame;
}
}
multi trait_mod:<is> (Attribute:D $attr, :$mooish!) {
note "Attribute's package.HOW: ", $attr.package.HOW;
note '$*PACKAGE.HOW: ', $*PACKAGE.HOW;
$attr.package.HOW does HOW1;
$*PACKAGE.HOW does HOW2;
}
class Foo {
has $.bar is mooish;
}
role FooRole {
has $.baz is mooish;
}
脚本的输出如下:
Attribute's package.HOW: Perl6::Metamodel::ClassHOW.new
$*PACKAGE.HOW: Perl6::Metamodel::ClassHOW.new
HOW2.compose
HOW1.compose
Attribute's package.HOW: Perl6::Metamodel::GenericHOW.new
$*PACKAGE.HOW: Perl6::Metamodel::ParametricRoleHOW.new
HOW2.compose
从输出中可以清楚地看出,将角色应用于元类始终适用于 类,并且仅适用于具有角色的 $*PACKAGE.HOW
。使用 $*PACKAGE
而不是 .package
可以被视为一种解决方案,但不是我真正想使用的解决方案。 (不过,如果没有更好的办法...)
存取器
我也想为私有属性提供惰性功能。是的,这仅适用于 self!bar
语法,但 这是我愿意做出的牺牲 。问题是到目前为止我发现的所有定制访问器示例都使用了 Attribute.set_value()
方法,这太低级了。我想要这样的东西:
role MooishHOW {
method compose ( Mu $class ) {
my $accessor = $class.^add_private_method( 'bar1',
method () is rw {
note self.WHO, ".bar1";
Proxy.new(
FETCH => -> $o {
$!bar1;
},
STORE => method ( $val ) {
note "Storing";
$!bar1 = $val;
}
);
}
);
callsame;
}
}
multi trait_mod:<is> (Attribute:D $attr, :$mooish!) {
$attr.package.HOW does MooishHOW unless $attr.package.HOW ~~ MooishHOW;
}
class Foo {
has $.bar is mooish;
has $!bar1 is mooish;
method to-bar1 {
note "bar1 val:",self!bar1;
}
}
my $inst = Foo.new;
$inst.to-bar1;
但是 $!bar1
表示法由于作用域 (MooishRole
) 而无法编译。是否有我遗漏的技巧允许在 self
上引用私有属性?
棘手的
也许可以将属性设为 Proxy
容器?这将大大简化懒惰实现的整体逻辑。
我已经回答了我所有的问题,最终实现了目标并发布了 AttrX::Mooish 模块。
到目前为止,第一个问题的答案是:不会。 $*PACKAGE
是目前唯一的方法。
第二个问题:没有答案,但最终代码还是要靠set_value()
棘手的一个碰巧是可能的:set_value()
将属性绑定到容器,从而可以绑定到 Proxy
对象。无需牺牲,私有属性可以直接访问,懒惰对其进行处理。
谢谢大家,你们的回答让我解决了一些粗糙的问题!
我要为新项目选择使用什么语言:Perl5 或 Perl6。到目前为止,除了缺少 Moo
的懒惰属性外,6 次获胜。我在模块中发现的两个实现缺少关键功能。因此,我尝试编写自己的实现。
角色与 Class
我遇到的第一个问题是角色中声明的 .package
属性的内容。考虑以下内容:
role HOW1 {
method compose ( Mu $class ) {
note "HOW1.compose";
nextsame;
}
}
role HOW2 {
method compose ( Mu $class ) {
note "HOW2.compose";
nextsame;
}
}
multi trait_mod:<is> (Attribute:D $attr, :$mooish!) {
note "Attribute's package.HOW: ", $attr.package.HOW;
note '$*PACKAGE.HOW: ', $*PACKAGE.HOW;
$attr.package.HOW does HOW1;
$*PACKAGE.HOW does HOW2;
}
class Foo {
has $.bar is mooish;
}
role FooRole {
has $.baz is mooish;
}
脚本的输出如下:
Attribute's package.HOW: Perl6::Metamodel::ClassHOW.new
$*PACKAGE.HOW: Perl6::Metamodel::ClassHOW.new
HOW2.compose
HOW1.compose
Attribute's package.HOW: Perl6::Metamodel::GenericHOW.new
$*PACKAGE.HOW: Perl6::Metamodel::ParametricRoleHOW.new
HOW2.compose
从输出中可以清楚地看出,将角色应用于元类始终适用于 类,并且仅适用于具有角色的 $*PACKAGE.HOW
。使用 $*PACKAGE
而不是 .package
可以被视为一种解决方案,但不是我真正想使用的解决方案。 (不过,如果没有更好的办法...)
存取器
我也想为私有属性提供惰性功能。是的,这仅适用于 self!bar
语法,但 这是我愿意做出的牺牲 。问题是到目前为止我发现的所有定制访问器示例都使用了 Attribute.set_value()
方法,这太低级了。我想要这样的东西:
role MooishHOW {
method compose ( Mu $class ) {
my $accessor = $class.^add_private_method( 'bar1',
method () is rw {
note self.WHO, ".bar1";
Proxy.new(
FETCH => -> $o {
$!bar1;
},
STORE => method ( $val ) {
note "Storing";
$!bar1 = $val;
}
);
}
);
callsame;
}
}
multi trait_mod:<is> (Attribute:D $attr, :$mooish!) {
$attr.package.HOW does MooishHOW unless $attr.package.HOW ~~ MooishHOW;
}
class Foo {
has $.bar is mooish;
has $!bar1 is mooish;
method to-bar1 {
note "bar1 val:",self!bar1;
}
}
my $inst = Foo.new;
$inst.to-bar1;
但是 $!bar1
表示法由于作用域 (MooishRole
) 而无法编译。是否有我遗漏的技巧允许在 self
上引用私有属性?
棘手的
也许可以将属性设为 Proxy
容器?这将大大简化懒惰实现的整体逻辑。
我已经回答了我所有的问题,最终实现了目标并发布了 AttrX::Mooish 模块。
到目前为止,第一个问题的答案是:不会。 $*PACKAGE
是目前唯一的方法。
第二个问题:没有答案,但最终代码还是要靠set_value()
棘手的一个碰巧是可能的:set_value()
将属性绑定到容器,从而可以绑定到 Proxy
对象。无需牺牲,私有属性可以直接访问,懒惰对其进行处理。
谢谢大家,你们的回答让我解决了一些粗糙的问题!