当前位置: 首页 > 知识库问答 >
问题:

特征、属性、角色和闭包

云育
2023-03-14

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

这个想法是一种属性特性,它在它所组成的类型对象上安装方法。这个问题最初是在私有方法上发现的,我希望它安装在属性声明的角色中。此时,我发现在某些条件下,无法调用从闭包引用标量的生成方法!很可能是因为关闭在运行时丢失。但最令人困惑的是,这种情况只会发生在角色身上,而且只会发生在一个角色正在消费另一个角色的情况下!

因此,以下是特质来源:

 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,它安装了一个公共方法pubattr-

compose_method_injectp6

 #!/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;
     }
 }

compose-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中的类似代码失败。如果首先执行来自FooRole的foo role测试,则会观察到相同的结果:

> 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)

还值得注意的是,从FolRoleHow安装的方法不会丢失其闭包并已成功执行

现在,再看另一个把戏。我将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)

UPD需要注意的另一件重要事情是,角色和类都故意按文件拆分,因为将它们都放在公共文件中可以使事情按预期工作。

顺便说一句,我不想深入其中,但在提取上述示例的原始代码中,我还使用设置了方法名称。set_name。名称是字符串,包括闭包中的$attr标量。在compose()中转储方法表会产生以设置名称为值的哈希值;在用户代码中转储相同的表会显示与上述类似的输出-使用

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


共有1个答案

段哲圣
2023-03-14

这并不是确切的答案,而是一个注释和bug的解决方法。好的,刚刚注意到:这是一个bug。虽然它不存在于Linux版本的rakudo中,但我只在macOS/darwin上观察到它。当然,这并不意味着其他平台不易受到攻击。

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

 类似资料:
  • 在OWL中,不可伸缩属性的子属性也是不可伸缩的吗?同样,非对称属性的子属性也是非对称的吗? 从逻辑上讲,它们应该是这样的,但我在OWL文档中找不到任何说明这种情况的内容。 考虑以下示例: 基于此本体,不允许出现以下情况,因为的父项是不可伸缩的: 但是是否也隐含地不反射性呢?换句话说,这是否也被禁止: 如果你认为一个属性是一组连接成对的点的箭头,那么不可反身仅仅意味着没有在同一个点开始和结束的箭头。

  • 我正在Rust中编写一个带有控制台提示界面的进程内存扫描器。 我需要扫描仪类型,如winapi扫描仪或ring0驱动程序扫描仪,所以我试图实现多态性。 目前我有以下结构: 将来,除了 之外,我还会有更多扫描仪类型,因此,如果我理解正确,我应该使用特征引用 (

  • 问题内容: 我正在调整我的一个宠物项目以提高其性能。我已经淘汰了探查器以识别热点,但是我认为对Python性能特性的了解要好一些,这将非常有用。 我想知道几件事: 一些现代的编译器拥有非常聪明的优化器,它们通常可以采用简单的代码,并使其运行速度比任何人工调整代码的尝试都要快。根据优化器的智能程度,使我的代码“哑巴”可能更好。 尽管Python是一种“解释”语言,但它确实可以编译为某种形式的字节码(

  • 我用openlayers 3在地图中上传了一个geojson文件。geojson文件是一个FeatureCollection,具有LineString类型的5个功能。如何为每个功能添加不同的颜色以区分路径?如果我将颜色添加到geojson文件的样式中,则不会读取该文件,如果我将颜色添加到笔划中,则所有功能都以单一颜色着色。 下面我添加代码。 谢谢 文件GEOJSON: "type":"Featur

  • 我正在使用云形成和yaml语法设置AWS ECS服务。 在某个时候,在相关的留档中有一个名为的属性,其定义如下: 角色 AWS标识和访问管理(IAM)角色的名称或ARN,该角色允许Amazon ECS容器代理调用负载平衡器。 注意:在某些情况下,可能需要添加对服务角色策略的依赖关系。有关详细信息,请参阅DependsOn属性中的IAM角色策略。必需:无类型:字符串更新需要:替换 由于我打算将特定服