Jim*_*ger 7 inheritance attributes raku
此代码按预期工作:
use v6.d;
class Foo {
has $.name;
submethod BUILD (:$!name = 'John') {};
}
my $f = Foo.new;
say $f;
# OUTPUT: Foo.new(name => "John")
Run Code Online (Sandbox Code Playgroud)
但是,当我添加:
class Bar is Foo {
submethod BUILD (:$!name = 'Jane') {};
}
my $b = Bar.new;
say $b;
Run Code Online (Sandbox Code Playgroud)
我收到此错误消息:
===抱歉!=== 编译 scrap.raku 时
出错 属性$!name
未在 Bar 类中
声明scratch.raku:14
如何在构建时分配默认值?
这是一种TWEAK
改编自 brian d foy 的书“Learning Raku”(以前的“Learning Perl6”)第 12 章:“类”的方法:
use v6.d;
class Foo {
has $!default-name = 'John';
has $.custom-name is rw;
submethod TWEAK (:$custom-name) {
self.custom-name = $custom-name // $!default-name;
};
}
my $f = Foo.new;
say $f;
put "This is class Foo with {$f.custom-name} as name.";
class Bar is Foo {}
my $b = Bar.new;
$b.custom-name = 'Jane';
say $b;
put "This is class Bar with {$b.custom-name} as name.";
Run Code Online (Sandbox Code Playgroud)
输出:
Foo.new(custom-name => "John")
This is class Foo with John as name.
Bar.new(custom-name => "Jane")
This is class Bar with Jane as name.
Run Code Online (Sandbox Code Playgroud)
当没有指定自定义名称时,上面的 Foo 类的“John”采用默认名称。在第二个示例中,Bar 类的“Jane”采用分配给它的自定义名称。
您可以修改class Bar
为拥有自己的default-name
和 自己的TWEAK
子方法。class Foo
那么原始方法和继承方法之间的唯一区别class Bar is Foo {}
似乎是声明$.default-name
为公共方法。
https://www.learningraku.com/2018/08/14/table-of-contents/
https://www.oreilly.com/library/view/learning-perl-6/9781491977675/
这是根据您的评论编辑的版本。这样,子类的默认值就在子类中设置,但如果需要也可以显式设置。
use v6.d;
class Foo {
has $.name = 'John'
}
class Bar is Foo {
method new( *%h ) {
%h<name> //= 'Jane';
nextwith( |%h )
}
}
Foo.new.say; # OUTPUT: Foo.new(name => "John")
Bar.new.say; # OUTPUT: Bar.new(name => "Jane")
Bar.new(name => 'Dora').say; # OUTPUT: Bar.new(name => "Dora")
Run Code Online (Sandbox Code Playgroud)
由于我之前的版本依赖于 TWEAK,所以我认为尝试这种方式也会很有趣。
class Foo {
has $!name;
multi method name { #getter
$!name
}
multi method name( $value ) { #setter
$!name = $value
}
submethod TWEAK {
$!name //= 'John'
}
method gist(::T:) { #captures type of its invocant
"{::T.^name}.new(name => \"$!name\")"
}
}
class Bar is Foo {
submethod TWEAK( :$name ) {
self.name: $name // 'Jane'
}
}
Foo.new.say; # OUTPUT: Foo.new(name => "John")
Bar.new.say; # OUTPUT: Bar.new(name => "Jane")
Bar.new(name => 'Dora').say; # OUTPUT: Bar.new(name => "Dora")
Run Code Online (Sandbox Code Playgroud)
这有点棘手,因为公共属性简写has $.name;
会自动生成(i)公共访问器 getter/setter 方法,以及(ii)用于轻松分配的代理,以及(iii)调整.gist
以便通过 快速轻松地查看所有公共属性.say
。但这些功能在施工完成之前还没有准备好。
因此,此示例必须具有具有has $!name;
私有属性的显式 setter/getter 多重方法。
公共属性简写就像 OO 的训练轮,它提供了基本 OO 作为透明数据结构的简单使用,并且学习曲线较低(如 Python)。回避这个问题就像通过适当的封装将 raku 置于更正式的 OO 模式中一样。当你攀登 OO 山时,通过继承、角色、委托、信任等,raku 温和地鼓励你变得更加正式。
这里我们需要这样做,以获得$!name
在构造过程中访问父类中属性的方法。
现在对于 Foo 的 TWEAK 子方法来说,通过分配给它的私有 $!name 来应用默认值已经很容易了。
现在 Bar 的 TWEAK 子方法可以使用 getter/setter,因为所有常规方法在 TWEAK 时都可用。(实际上,如果在此示例中使用 BUILD 而不是 TWEAK,您会得到相同的结果。)
其他一些调整 -
.gist
我们需要显式地将私有属性放回自定义中.gist
::T
类型捕获,这样我只需要做一次,并且相同的父方法适用于所有子类self.
而不是$.
在 TWEAK 时使用(所有$.
虚拟方法机制都在之后出现),并且self.name: 'value'
(IMO 是一个更好的方法self.name('value')
),因为公共 attr 代理不存在编辑后,以下内容有点断章取义,但无论如何我都会离开这里。
神奇的是,特殊方法 new、BUILD 和 TWEAK 将仅根据其签名自动设置命名属性。
这就是为什么我更喜欢使用 TWEAK 而不是 BUILD:
BUILD 可以设置属性,但它无权访问声明为其默认值的属性的内容,因为它们仅在以后应用。另一方面,TWEAK 在应用默认值后调用,因此会发现属性已初始化。因此它可以用来在对象构造后检查事物或修改属性。