如何在Raku子类中初始化继承属性并设置构造默认值?
为Raku子类中继承的属性设置构造默认值
问题场景
父类代码运行完全符合预期:
use v6.d; class Foo { has $.name; submethod BUILD (:$!name = 'John') {}; } my $f = Foo.new; say $f; # OUTPUT: Foo.new(name => "John")
但添加子类代码后出现编译错误:
class Bar is Foo { submethod BUILD (:$!name = 'Jane') {}; } my $b = Bar.new; say $b;
错误信息:
=SORRY!= Error while compiling scratch.raku
Attribute$!namenot declared in class Bar
atscratch.raku:14
问题原因
Raku中以$!开头的私有属性是类级私有的,即使子类继承了父类,也无法直接通过$!name访问父类的同名属性——编译器会认为你在引用子类自身未声明的属性,因此报错。
解决方案
以下三种方法都可以实现子类构造时为继承的属性设置默认值:
方案1:通过父类限定符直接赋值
在子类的BUILD方法中,明确指定父类的属性进行赋值:
class Bar is Foo { submethod BUILD { $!Foo::name = 'Jane'; } }
$!Foo::name直接指向父类Foo中定义的$!name属性,赋值后即可覆盖父类的默认值。
方案2:在BUILD参数中绑定父类属性
通过参数绑定的方式,将构造参数直接关联到父类属性,并设置默认值:
class Bar is Foo { submethod BUILD (:name($!Foo::name) = 'Jane') {} }
这种写法既简洁,同时支持外部通过Bar.new(name => 'CustomName')传入自定义属性值。
方案3:重新声明属性并标记为继承
如果希望在子类中沿用$!name的写法,可以重新声明属性并添加is inherited特质,这样子类的$!name会复用父类的属性:
class Bar is Foo { has $.name is inherited; submethod BUILD (:$!name = 'Jane') {} }
这种方式保持了代码风格的一致性,同时允许子类自定义默认值。
测试结果
使用任意一种方案后,运行代码都会得到预期输出:
Bar.new(name => "Jane")
内容的提问来源于stack exchange,提问作者Jim Bollinger
相关产品推荐
相关产品推荐

