该线程中给出的代码不再起作用:How can I rebless an object in Perl 6?
我去年写过这段代码,然后就起作用了。现在没有:
class Person { ; }
class Woman is Person { ; }
my $tom = Person.new;
my $lisa = Woman.new;
say $tom.^name; # -> Person
say $lisa.^name; # -> Woman
Metamodel::Primitives.rebless($tom, Woman);
# -> New type Woman for Person is not a mixin type
该错误消息没有意义,因为它应该与继承的类一起使用。
至少是。
该文档没有帮助; https://docs.raku.org/routine/rebless
最佳答案
从来没有那样的笼统。我设计了该API并首先实现了该API,但它仅被用作mixin的实现细节。
直到最近,它还不是语言规范测试套件的一部分-当它成为语言规范测试套件的一部分时,它已经具有当前的,更具限制性的语义。出于性能原因,对此的约束很重要:当我们知道某个类型不是可以作为mixin操作目标的类型时,我们可以将该对象的属性访问JIT编译为更简单的操作(我们在操作上付出了额外的条件转移)更改之前的每个属性访问权限,现在只需要按mixin目标类型付费即可)。
通过使用MOP构造类,可以修改原始程序以使其正常工作。实际上,以下内容并非原始程序;为了说明如何在子类中以匿名角色的方式提供方法,我做了一些小调整,以避免出现过多的MOP样板。
class Person { method m() { "person" } }
constant Woman = do {
my \w = Metamodel::ClassHOW.new_type(:is_mixin, :name<Woman>);
w.^add_parent(Person);
w.^add_role(role { method m() { "woman" } });
w.^compose()
}
my $tom = Person.new;
my $lisa = Woman.new;
say $tom.^name; # -> Person
say $lisa.^name; # -> Woman
say $tom.m; # person
Metamodel::Primitives.rebless($tom, Woman);
say $tom.m; # woman
虽然这是对原始程序的最直接的语义修复,但是有一种较短的方法:在
but
类型对象上使用Person
运算符生成混合类型并返回它,然后根据自己的喜好调整其名称:class Person { method m() { "person" } }
constant Woman = Person but role { method m() { "woman" } }
BEGIN Woman.^set_name('Woman');
my $tom = Person.new;
my $lisa = Woman.new;
say $tom.^name; # -> Person
say $lisa.^name; # -> Woman
say $tom.m;
Metamodel::Primitives.rebless($tom, Woman);
say $tom.m;
无论如何,这只比原始线多了一行。
关于Raku rebless不再适用于继承的类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59845201/