【发布时间】:2020-01-02 18:13:51
【问题描述】:
假设我有一个具有多个属性的类,但我只需要其中一些属性来构建对象;其余属性的值取决于这些 public 属性。但是,我仍然想使用以属性命名的方法来访问其余属性的值。在我的脑海中,有两个选择:
第一个选项:
- 重载
new方法。或者保持new方法不变,而是使用BUILD子方法将传递的参数设置为正确的属性,并使用此参数的值设置剩余的属性。
class Foo {
has Int $.a;
has Int $.b;
has Int $.c;
submethod BUILD(:$!a) {
$!b = $!a ** 2;
$!c = $!a ** 3;
}
}
say Foo.new(:2a, :1b); #=> Foo.new(a => 2, b => 4, c => 8)
say Foo.new(:2a, :1b).b; #=> 8
第二个选项:
仅使用$. 声明对象构造所需的属性,并在对象构造后使用TWEAK 子方法修改其余属性(使用$! 声明)。但是,现在我需要为这些属性创建访问器方法。
class Bar {
has Int $.a;
has Int $!b;
has Int $!c;
submethod TWEAK {
$!b = $!a ** 2;
$!c = $!a ** 3;
}
method b { $!b }
method c { $!c }
}
say Bar.new(:2a, :1b); #=> Bar.new(a => 2)
say Bar.new(:2a, :1b).b; #=> 8
问题
最好的选项是什么?还有其他选择吗?每个选项的优点/缺点是什么?
【问题讨论】:
-
考虑到传递
b和c参数对对象创建没有影响,我觉得有些奇怪,有人会发现Foo.new(a => 2, b => 4, c => 8)的.perl输出是可以接受的。 -
也许属性上的“可访问”特征会自动对私有属性执行选项 2?我去过那个地方很多次了。
-
在解决问题的仓库中添加了一个问题:github.com/perl6/problem-solving/issues/145
-
已实现并放入 PR:github.com/rakudo/rakudo/pull/3404
-
它现在作为
is built在核心中:$!a is built现在允许您使用.new设置私有访问器,但无需为其创建访问器。$.a is built(False)将为属性创建一个访问器,但会禁止使用.new设置它。
标签: class oop attributes raku