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

标签 oop traits raku

对于我正在编写的库,我有一个使用 handles 的 HOW 属性。将由另一个 HOW 完成的各种角色的方法委托(delegate)给该 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 ∌ *)
};

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

最佳答案

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

Raku 中的常量不仅仅是在声明它们之后无法分配或绑定(bind)的变量。通常,当您声明一个变量时,它的符号是在编译期间安装的,但它的值直到运行时才真正设置,这就是为什么会发生这种情况:

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_OVERRIDES 这样的符号和 PARENT_METHODS不应该存在于类型的上下文中,您仍然可以通过声明常量并从闭包中添加属性来以这种方式处理特征;方法和属性声明的范围是这样的,您可以从类型包中的任何位置编写它们,并且仍然可以将它们添加到类型中。请记住,方法和属性是在编译期间处理的,因此这不是您处理诸如为类型动态生成属性或方法之类的事情的方式。

关于oop - 如何动态生成用于特征的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58673170/

相关文章:

c++ - 在 C++ 中使用特征

java - 我应该使用 Abstract 或 Interface ...还是从应该扩展的具体类开始?

scala - 为什么 trait 方法需要 asInstanceOf 而类方法不需要

c++ - 为什么一个类不能对函数和数据成员具有相同的名称?

c++ - 根据模板参数使用不同的函数集(C++ 特征?)

使用 Perl6 打包和解包数据结构

regex - 我可以内省(introspection)正则表达式的插值吗?

raku - 如何创建和导出动态运算符

language-agnostic - 数据和代码有什么区别?

javascript - 如何区分方法和函数?