Làm thế nào bạn có thể tự động tạo ra các giá trị để sử dụng với các đặc điểm?


8

Đối với một thư viện tôi đang viết, tôi có một thuộc tính trên CÁCH sử dụng handlesđặc điểm để ủy thác các phương thức của các vai trò khác nhau được thực hiện bởi một CÁCH khác mà nó sử dụng cho một thể hiện của CÁCH đó. Nỗ lực đầu tiên của tôi trông như thế này (mặc dù để làm cho nó dễ đọc hơn, điều này sẽ chỉ giải quyết 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

Vấn đề với điều này là nếu bất kỳ loại nào tôi thực hiện CÁCH này xử lý các phương thức cho từng thay đổi, thì điều này sẽ không còn hoạt động với tất cả các phương thức của chúng. Vì vậy, thay vào đó tôi muốn tự động tạo ra một danh sách các phương thức nên được xử lý đưa ra một danh sách các phương thức mà CÁCH này ghi đè và một danh sách các loại có phương thức nên được xử lý. Điều này không dễ dàng như âm thanh vì cách handlestính trạng được thực hiện. Ví dụ, điều này sẽ không hoạt động:

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 ∌ *)
};

Vì vậy, làm thế nào bạn có thể tự động tạo ra một giá trị cho một đặc điểm để sử dụng trong các trường hợp như thế này?

Câu trả lời:


7

Ứng dụng Trait được thiết lập trong quá trình biên dịch, vì vậy chúng ta cũng cần một cách để tạo ra một giá trị cho nó để sử dụng trong quá trình biên dịch. Điều này có thể được thực hiện bằng cách sử dụng BEGINphaser, nhưng điều này được viết tốt hơn constanttrong trường hợp này.

Các hằng số trong Raku không chỉ là các biến bạn không thể gán hoặc liên kết sau khi khai báo chúng. Thông thường, khi bạn khai báo một biến, biểu tượng của nó được cài đặt trong quá trình biên dịch, nhưng giá trị của nó không thực sự được đặt cho đến khi chạy, đó là lý do tại sao điều này có thể xảy ra:

my Int:D $foo = 1;

BEGIN say $foo; # OUTPUT: (Int)

Đây không phải là trường hợp với constant ; trình biên dịch đặt giá trị của ký hiệu trong quá trình biên dịch. Điều này có nghĩa là đối với ví dụ trong câu hỏi, chúng ta có thể tự động tạo một danh sách các phương thức handlesđể sử dụng như thế này:

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;

Nếu vì lý do nào đó biểu tượng như PARENT_METHOD_OVERRIDESPARENT_METHODS không nên tồn tại trong ngữ cảnh của loại, bạn vẫn có thể xử lý các đặc điểm theo cách này bằng cách khai báo các hằng số và thêm các thuộc tính từ trong một bao đóng; khai báo phương thức và thuộc tính được đặt trong phạm vi sao cho bạn có thể viết chúng từ bất kỳ đâu trong gói của loại và vẫn có thể thêm chúng vào loại. Hãy nhớ rằng các phương thức và thuộc tính được xử lý trong quá trình biên dịch, vì vậy đây không phải là cách bạn sẽ xử lý một cái gì đó như các thuộc tính hoặc phương thức tạo động cho một kiểu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.