raku 内置访问器方法可以被子 class 覆盖吗?
Can the raku built in accessor methods be overridden by a child class?
我正在尝试 'override' raku 为 public $ 生成的内置访问器。属性。但是,我可以使用一些帮助来尝试找出此代码失败的原因...
class Measure {
has $.value is rw
}
class Angle is Measure {
multi method value( $x ) {
nextwith( $x % 360 );
}
}
my $m = Measure.new( value => 27 );
$m.value = 42;
say $m; #Measure.new(value => 42)
my $a = Angle.new( value => 27 );
$a.value = 43;
say $a; #Error...
Cannot resolve caller value(Angle:D: ); none of these signatures match:
(Angle: $x, *%_)
你的指导会很有帮助!
当您使用 .
将属性声明为 public 时,Raku 将创建一个同名方法。
该方法不带任何参数。
即使是rw
.
(如果您将属性声明为 is rw
,那么生成的方法就是实际标记为 is rw
的方法。)
当您使用 nextwith
时,它会分派到父 class 中的方法。
在这种情况下,该方法不带任何参数。
以下是至少有效的方法:
class Angle is Measure {
method value( $x ) {
callwith() = $x % 360;
}
}
my $a = Angle.new( value => 27 );
#$a.value = 43;
$a.value(43);
当然这意味着 Angle.value
不像 Measure.value
那样是 左值 。
(lvalue表示可以在=
左边。)
那么让我们开始吧。
由于我们需要在调用 .value
的过程中进行计算,因此我们需要 return 一个 Proxy
class Angle is Measure {
method value() is rw {
Proxy.new:
FETCH => -> $ { self.Measure::value },
STORE => -> $, $x {
self.Measure::value = $x % 360;
}
}
}
请注意,我们不能只在这些块中使用 callsame
或类似的东西,因为它们会启动一个新的调度链。
相反,我们需要调用 Measure
class.
中的方法版本
如果将该调用的结果绑定到用作闭包一部分的变量,则可以使用 callsame
或类似的方法。
(我使用 $attr
因为它绑定到实际属性标量。)
class Angle is Measure {
method value is rw {
my $attr := callsame();
Proxy.new:
FETCH => -> $ { $attr },
STORE => -> $, $x {
$attr = $x % 360;
}
}
}
我个人认为 Measure
应该是一个角色,因为这使事情变得更容易,因为您可以直接访问该属性。
role Measure {
has $.value is rw
}
class Angle does Measure {
method value() {
Proxy.new:
FETCH => -> $ { $!value },
STORE => -> $, $x {
$!value = $x % 360;
}
}
}
我也有一个问题,角度被声明为一个数字,但没有说它是以度为单位,而不是说弧度或弧度。
实际上你甚至没有声明它是一个数字。
所以我可能会尝试这样的事情:
role Measure {
has Real $.value is rw;
}
role Angle {…}
class Degrees {…}
class Radians {…}
class Gradians {…}
role Angle does Measure {
method Degrees ( --> Degrees ) {…}
method Radians ( --> Radians ) {…}
method Gradians ( --> Gradians ) {…}
}
class Degrees does Angle {
method value() {
Proxy.new:
FETCH => -> $ { $!value },
STORE => -> $, $x {
$!value = $x % 360;
}
}
method Degrees () { self }
method Radians () { !!! } # needs to actually be implemented here
method Gradians () { !!! }
}
class Radians does Angle {
method value() {
Proxy.new:
FETCH => -> $ { $!value },
STORE => -> $, $x {
$!value = $x % τ;
}
}
method Degrees () { !!! }
method Radians () { self }
method Gradians () { !!! }
}
class Gradians does Angle {
method value() {
Proxy.new:
FETCH => -> $ { $!value },
STORE => -> $, $x {
$!value = $x % 400;
}
}
method Degrees () { !!! }
method Radians () { !!! }
method Gradians () { self }
}
老实说,我也不喜欢那样,因为您将值视为容器。
基本上你是这样工作的,你不能有一个恒定的角度。
class Foo {
has Angle $.bar;
}
my $foo = Foo.new( bar => Degrees.new( value => 27 ) );
$foo.bar.angle = 43;
我认为你应该要求它像这样工作,在这里你可以选择角度是否恒定。
class Foo {
has Angle $.bar is rw;
}
my $foo = Foo.new( bar => Degrees.new( value => 27 ) );
$foo.bar .= new( value => 43 );
这样做会让你直接删除所有子class中的value
方法,并用一个简单的TWEAK
替换它们.
(无论如何,这是您真正需要的东西。)
当然,您还需要从 $.value
.
中删除 is rw
我会这样做,这样你就可以只用一个值而不是 value => 27
.
来调用 .new
role Measure {
has Real $.value;
multi method new ( $value ) {
samewith( :$value )
}
}
role Angle {…}
class Degrees {…}
class Radians {…}
class Gradians {…}
role Angle does Measure {
method Degrees ( --> Degrees ) {…}
method Radians ( --> Radians ) {…}
method Gradians ( --> Gradians ) {…}
}
class Degrees does Angle {
submethod TWEAK { $!value %= 360 }
method Degrees () { self }
method Radians () { !!! } # needs to actually be implemented here
method Gradians () { !!! }
}
class Radians does Angle {
submethod TWEAK { $!value %= τ }
method Degrees () { !!! }
method Radians () { self }
method Gradians () { !!! }
}
class Gradians does Angle {
submethod TWEAK { $!value %= 400 }
method Degrees () { !!! }
method Radians () { !!! }
method Gradians () { self }
}
class Foo {
has Angle $.bar is rw;
}
my $foo = Foo.new( bar => Degrees.new( 27 ) );
$foo.bar = Degrees.new( 43 );
关于最后一个版本,我希望您注意一些事情。
那里[几乎]没有代码。
它主要是声明性代码,当它出错时往往会更加明显。
(你需要用!!!
填写这些部分,但那里的代码不应该太多。)
无论如何,我的观点是,是的,你 可以 [使用 Proxy
] 做到这一点,但这是有原因的,它更难。
你看问题的方向在某种程度上违背了Raku的设计理念。
我正在尝试 'override' raku 为 public $ 生成的内置访问器。属性。但是,我可以使用一些帮助来尝试找出此代码失败的原因...
class Measure {
has $.value is rw
}
class Angle is Measure {
multi method value( $x ) {
nextwith( $x % 360 );
}
}
my $m = Measure.new( value => 27 );
$m.value = 42;
say $m; #Measure.new(value => 42)
my $a = Angle.new( value => 27 );
$a.value = 43;
say $a; #Error...
Cannot resolve caller value(Angle:D: ); none of these signatures match:
(Angle: $x, *%_)
你的指导会很有帮助!
当您使用 .
将属性声明为 public 时,Raku 将创建一个同名方法。
该方法不带任何参数。
即使是rw
.
(如果您将属性声明为 is rw
,那么生成的方法就是实际标记为 is rw
的方法。)
当您使用 nextwith
时,它会分派到父 class 中的方法。
在这种情况下,该方法不带任何参数。
以下是至少有效的方法:
class Angle is Measure {
method value( $x ) {
callwith() = $x % 360;
}
}
my $a = Angle.new( value => 27 );
#$a.value = 43;
$a.value(43);
当然这意味着 Angle.value
不像 Measure.value
那样是 左值 。
(lvalue表示可以在=
左边。)
那么让我们开始吧。
由于我们需要在调用 .value
的过程中进行计算,因此我们需要 return 一个 Proxy
class Angle is Measure {
method value() is rw {
Proxy.new:
FETCH => -> $ { self.Measure::value },
STORE => -> $, $x {
self.Measure::value = $x % 360;
}
}
}
请注意,我们不能只在这些块中使用 callsame
或类似的东西,因为它们会启动一个新的调度链。
相反,我们需要调用 Measure
class.
如果将该调用的结果绑定到用作闭包一部分的变量,则可以使用 callsame
或类似的方法。
(我使用 $attr
因为它绑定到实际属性标量。)
class Angle is Measure {
method value is rw {
my $attr := callsame();
Proxy.new:
FETCH => -> $ { $attr },
STORE => -> $, $x {
$attr = $x % 360;
}
}
}
我个人认为 Measure
应该是一个角色,因为这使事情变得更容易,因为您可以直接访问该属性。
role Measure {
has $.value is rw
}
class Angle does Measure {
method value() {
Proxy.new:
FETCH => -> $ { $!value },
STORE => -> $, $x {
$!value = $x % 360;
}
}
}
我也有一个问题,角度被声明为一个数字,但没有说它是以度为单位,而不是说弧度或弧度。
实际上你甚至没有声明它是一个数字。
所以我可能会尝试这样的事情:
role Measure {
has Real $.value is rw;
}
role Angle {…}
class Degrees {…}
class Radians {…}
class Gradians {…}
role Angle does Measure {
method Degrees ( --> Degrees ) {…}
method Radians ( --> Radians ) {…}
method Gradians ( --> Gradians ) {…}
}
class Degrees does Angle {
method value() {
Proxy.new:
FETCH => -> $ { $!value },
STORE => -> $, $x {
$!value = $x % 360;
}
}
method Degrees () { self }
method Radians () { !!! } # needs to actually be implemented here
method Gradians () { !!! }
}
class Radians does Angle {
method value() {
Proxy.new:
FETCH => -> $ { $!value },
STORE => -> $, $x {
$!value = $x % τ;
}
}
method Degrees () { !!! }
method Radians () { self }
method Gradians () { !!! }
}
class Gradians does Angle {
method value() {
Proxy.new:
FETCH => -> $ { $!value },
STORE => -> $, $x {
$!value = $x % 400;
}
}
method Degrees () { !!! }
method Radians () { !!! }
method Gradians () { self }
}
老实说,我也不喜欢那样,因为您将值视为容器。
基本上你是这样工作的,你不能有一个恒定的角度。
class Foo {
has Angle $.bar;
}
my $foo = Foo.new( bar => Degrees.new( value => 27 ) );
$foo.bar.angle = 43;
我认为你应该要求它像这样工作,在这里你可以选择角度是否恒定。
class Foo {
has Angle $.bar is rw;
}
my $foo = Foo.new( bar => Degrees.new( value => 27 ) );
$foo.bar .= new( value => 43 );
这样做会让你直接删除所有子class中的value
方法,并用一个简单的TWEAK
替换它们.
(无论如何,这是您真正需要的东西。)
当然,您还需要从 $.value
.
is rw
我会这样做,这样你就可以只用一个值而不是 value => 27
.
.new
role Measure {
has Real $.value;
multi method new ( $value ) {
samewith( :$value )
}
}
role Angle {…}
class Degrees {…}
class Radians {…}
class Gradians {…}
role Angle does Measure {
method Degrees ( --> Degrees ) {…}
method Radians ( --> Radians ) {…}
method Gradians ( --> Gradians ) {…}
}
class Degrees does Angle {
submethod TWEAK { $!value %= 360 }
method Degrees () { self }
method Radians () { !!! } # needs to actually be implemented here
method Gradians () { !!! }
}
class Radians does Angle {
submethod TWEAK { $!value %= τ }
method Degrees () { !!! }
method Radians () { self }
method Gradians () { !!! }
}
class Gradians does Angle {
submethod TWEAK { $!value %= 400 }
method Degrees () { !!! }
method Radians () { !!! }
method Gradians () { self }
}
class Foo {
has Angle $.bar is rw;
}
my $foo = Foo.new( bar => Degrees.new( 27 ) );
$foo.bar = Degrees.new( 43 );
关于最后一个版本,我希望您注意一些事情。
那里[几乎]没有代码。
它主要是声明性代码,当它出错时往往会更加明显。
(你需要用!!!
填写这些部分,但那里的代码不应该太多。)
无论如何,我的观点是,是的,你 可以 [使用 Proxy
] 做到这一点,但这是有原因的,它更难。
你看问题的方向在某种程度上违背了Raku的设计理念。