gpt4 book ai didi

raku - 特征、属性、角色和闭包

转载 作者:行者123 更新时间:2023-12-04 21:03:40 25 4
gpt4 key购买 nike

我将继续探索 Perl6 微妙的实现细节。这次我在将自己的方法安装到角色中时遇到了问题。当我们开始进入代码的旅程时,请系好安全带。

这个想法是一个属性特征,它在它被组合成的类型对象上安装方法。问题最初是在私有(private)方法上发现的,我希望将其安装在声明属性的角色中。那时我发现在某些条件下,无法调用从闭包中引用标量的生成方法!很可能是由于关闭在运行时丢失。但最令人困惑的一点是,它只发生在角色身上,而且只有一个角色正在消费另一个角色!

所以,这里是特征来源:

 unit module trait-foo;

role FooClassHOW {...}

role FooAttr {
has $.base-name = self.name.substr(2);
method compose (Mu \type) {
callsame;
if (type.HOW ~~ Metamodel::ClassHOW) && (type.HOW !~~ FooClassHOW) {
type.HOW does FooClassHOW;
}
}

method install-method ( Mu \type ) {
my $attr = self;
type.^add_private_method(
"attr-{$attr.base-name}",
method { "by attr {$attr.name}" }
);
type.^add_method(
"pubattr-{$attr.base-name}",
method { "by attr {$attr.name} - public" }
);
type.^add_private_method(
"check-{$attr.base-name}",
method { "not using closure" }
);
}
}

role FooClassHOW {
method compose ( Mu \type ) {
for type.^attributes.grep( FooAttr ) -> $attr {
$attr.install-method( type );
type.^add_private_method(
"class-{$attr.base-name}",
method { "by class: attr {$attr.name}" }
);
}
nextsame;
}
}

role FooRoleHOW {
method compose ( Mu \type ) {
for type.^attributes.grep( FooAttr ) -> $attr {
$attr.install-method( type );
type.^add_private_method(
"role-{$attr.base-name}",
method { "by role: attr {$attr.name}" }
);
}
nextsame;
}
}

multi trait_mod:<is> (Attribute:D $attr, :$foo!) is export {
$attr does FooAttr;
given $*PACKAGE.HOW {
when Metamodel::ParametricRoleHOW {
$_ does FooRoleHOW unless $_ ~~ FooRoleHOW;
}
default {
$_ does FooClassHOW unless $_ ~~ FooClassHOW;
}
}
}

这里的关键点是 install-method安装公共(public)方法 pubattr-<attr> , 和私有(private)方法 attr-<attr> , check-<attr> . pubattr- 之间的区别, attr-check-是前两个指的是他们的关闭,而后者没有。如果在各自的文件中定义了两个角色和一个类,会发生以下情况:

compose_method_inject.p6
 #!/usr/bin/env perl6
use lib '.';
use trait-foo;
use compose-foorole;

class Foo does FooRole {
has $.fubar is foo;

method class-test {
say self!check-fubar;
say self!class-fubar;
say self!attr-fubar;
}
}

my $inst = Foo.new;
note "> Class";
$inst.class-test;
note "> BarRole";
$inst.bar-role-test;
note "> FooRole";
$inst.foo-role-test;

撰写-foorole.pm6
 unit package compose;
use trait-foo;
use compose-barrole;

role FooRole does BarRole is export {
has $.foo is foo;

method foo-role-test {
note FooRole.^candidates[0].^private_method_table;
say self!check-foo;
say self!role-foo;
say self!attr-foo;
}
}

撰写-barrole.pm6
unit package compose;
use trait-foo;

role BarRole is export {
has $.bar is foo;

method bar-role-test {
note BarRole.^candidates[0].^private_method_table;
say self!check-bar;
say self!role-bar;
say self!inattr-bar;
}
}

执行 compose_method_inject.p6 会产生以下输出:

> Class
not using closure
by class: attr $!fubar
by attr $!fubar
by attr $!fubar - public
> BarRole
{attr-bar => <anon>, check-bar => <anon>, role-bar => <anon>}
not using closure
by role: attr $!bar
Cannot invoke this object (REPR: Null; VMNull)


请注意,该类工作正常,而 BarRole 中的类似代码失败。如果 foo-role-test 将观察到相同的结果来自 FooRole首先执行:

> Class
not using closure
by class: attr $!fubar
by attr $!fubar
by attr $!fubar - public
> FooRole
{attr-foo => <anon>, check-foo => <anon>, role-foo => <anon>}
not using closure
by role: attr $!foo
Cannot invoke this object (REPR: Null; VMNull)


还值得注意的是,从 FooRoleHOW 安装的方法不会失去它的关闭并被成功执行。

现在,到另一个技巧。我删除 does BarRole来自 FooRole并使其直接应用于 Foo:
class Foo does FooRole does BarRole {

输出发生巨大变化,情况变得更加困惑:

> Class
not using closure
by class: attr $!fubar
by attr $!fubar
by attr $!fubar - public
> FooRole
{attr-foo => <anon>, check-foo => <anon>, role-foo => <anon>}
not using closure
by role: attr $!foo
by attr $!foo
> BarRole
{attr-bar => <anon>, check-bar => <anon>, role-bar => <anon>}
not using closure
by role: attr $!bar
Cannot invoke this object (REPR: Null; VMNull)


更新 另一个需要注意的重要事情是角色和类都故意按文件拆分,因为将它们全部放在公共(public)文件中会使事情按预期工作。

顺便说一句,我不想​​更深入地了解它,但是在从中提取上述示例的原始代码中,我还使用 .set_name 设置方法名称.名称是字符串,包括 $attr闭包的标量。 compose() 中的转储方法表正在生成以集合名称作为值的散列;在用户代码中转储相同的表会显示与上述类似的输出 - 带有 <anon>作为值(value)观。看起来,方法名称与闭包一起被 GC'ed。

现在,我想听听有人说我很愚蠢,必须以不同的方式安装方法。或者关于属性的信息必须以其他方式保存,而不是通过依赖闭包。或者任何其他可以让我创建私有(private)属性相关方法的想法。

最佳答案

这并不完全是答案,而是该错误的注释和解决方法。好的,刚刚做了注释:这是一个错误。虽然它不存在于 Linux 版本的 rakudo 中,但我只在 macOS/darwin 上观察到它。当然,这并不意味着其他平台没有漏洞。

该错误有一个解决方法。由于从类/角色 Composer 安装的方法不会丢失它们的闭包,因此必须将方法的安装移入其中。在我的例子中,因为两者都需要类似的功能,所以使用角色实现方法安装程序很有魅力。

关于raku - 特征、属性、角色和闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52227483/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com