如何动态生成用于特征的值?

问题描述 投票:0回答:1

对于我正在编写的库,我在HOW上有一个属性,该属性使用handles特性将由其使用的另一种HOW所完成的各种角色的方法委托给该HOW的实例。我的第一次尝试是这样的(尽管为了使它更容易阅读,这只会处理Metamodel::Naming):

class ParentHOW does Metamodel::Naming {
    method new_type(ParentHOW:_: Str:D :$name!, Str:D :$repr = 'P6opaque' --> Mu) {
        my ::?CLASS:D $meta := self.new;
        my Mu         $type := Metamodel::Primitives.create_type: $meta, $repr;
        $meta.set_name: $type, $name;
        $type
    }
}

class ChildHOW {
    has Mu $!parent;
    has Mu $!parent_meta handles <set_name shortname set_shortname>;

    submethod BUILD(ChildHOW:D: Mu :$parent is raw) {
        $!parent      := $parent;
        $!parent_meta := $parent.HOW;
    }

    method new_type(ChildHOW:_: Mu :$parent is raw) {
        my ::?CLASS:D $meta := self.new: :$parent;
        Metamodel::Primitives.create_type: $meta, $parent.REPR
    }

    method name(ChildHOW:D: Mu \C --> Str:_) { ... }
}

my Mu constant Parent = ParentHOW.new_type: :name<Parent>;
my Mu constant Child  = ChildHOW.new_type:  :parent(Parent);

say Child.^shortname; # OUTPUT: Parent

问题是,如果我使HOW处理的所有类型中的任何一种都可以随时更改方法,那么它将不再适用于所有方法。因此,我想动态地生成给定该HOW覆盖的方法列表和应处理其方法的类型的列表。由于如何实现handles特性,这并不像听起来那样容易。例如,这将不起作用:

has Mu $!parent_meta handles do {
    my Array[Str:D] constant PARENT_METHOD_OVERRIDES .= new: <name>;

    ((), Metamodel::Naming)
        .reduce({ (|$^methods, |$^role.HOW.methods: $^role) })
        .map(*.name)
        .grep(PARENT_METHOD_OVERRIDES ∌ *)
};

那么您将如何动态生成特征的值以在这种情况下使用?

oop traits perl6 raku
1个回答
0
投票

特质应用程序是在编译期间设置的,因此我们需要一种方法来生成一个值,供其在编译期间使用。这可以使用BEGIN移相器完成,但是在这种情况下,最好用constant编写。

Raku中的常量不仅仅是声明后不能分配或绑定到的变量。通常,在声明变量时,将在编译过程中安装其符号,但是直到运行时才真正设置其值,这就是为什么会发生这种情况:

my Int:D $foo = 1;

BEGIN say $foo; # OUTPUT: (Int)

constant并非如此;编译器在编译过程中设置符号的值。这意味着对于问题中的示例,我们可以动态生成一个供handles使用的方法列表,如下所示:

my Array[Str:D] constant PARENT_METHOD_OVERRIDES .= new: <name>;
my Array[Str:D] constant PARENT_METHODS          .= new:
    ((), Metamodel::Naming)
        .reduce({ (|$^methods, |$^role.HOW.methods: $^role) })
        .map(*.name)
        .grep(PARENT_METHOD_OVERRIDES ∌ *);

has Mu $!parent;
has Mu $!parent_meta handles PARENT_METHODS;

如果由于某种原因在类型的包中没有PARENT_METHOD_OVERRIDESPARENT_METHODS之类的符号,则仍可以通过声明常量并在闭包内添加属性来以这种方式处理特征。方法和属性声明的默认范围是our,因此您可以在类型包中的任何位置编写它们,并且仍然可以将它们添加到类型中。请记住,方法和属性是在编译期间处理的,因此,这不是处理诸如为类型动态生成属性或方法之类的方法。

© www.soinside.com 2019 - 2024. All rights reserved.