我想为一个属性赋予特征,以为其提供代理,以便即使$!direct-access在一个类中也可以操纵所见内容的值。
这就是我现在所拥有的,但是正如您所看到的,从未调用过实际的get / set或store / fetch方法。我可能没有正确地应用它们,但是我发现的唯一示例似乎有大量额外的代码,它们的工作方式超出了我的需要,但我无法隔离重要的部分。
# The below shows on a Str more or less how I'd expect things to work
# although the %data wouldn't be hard coded of course
my Str $localized := do {
my %data = hi => "hola", bye => "adiós";
my $str = "";
Proxy.new:
:STORE{ $str = @_[1] },
:FETCH{ with %data{$str} { $_ } else { $str } }
}
$localized = "hi";
say $localized;
$localized = "bye";
say $localized;
$localized = "not defined";
say $localized;
# This seems to almost work,
multi trait_mod:<is>(Attribute:D $a, :$localized!) {
say $a.container.VAR.WHAT;
$a.container.VAR does role Localized {
has $!str;
method STORE($a) { say "store!"; $!str = $a }
method FETCH {say "fetch!"}
}
}
class Foo {
has Str $.text is localized;
}
my $foo = Foo.new;
say $foo.text, " <-- should be in Spanish";
$foo.text = "bye";
say $foo.text, " <-- should be in Spanish";
Run Code Online (Sandbox Code Playgroud)
尽管在这种情况下STORE正确地调用了该方法,但fetch方法却未正确调用,而is的要点$foo.text是Scalar+{Localized}.new,这表明我不太正确地应用东西。
您需要安排Proxy将其绑定到属性中,以便存在一个类Proxy,而不是Scalar通常由类初始化逻辑创建的容器。这可以通过设置构建逻辑来实现(尽管如果采用这种方法,您将覆盖任何初始默认值),并Proxy在每次创建对象时使用该逻辑将属性绑定到新属性:
multi trait_mod:<is>(Attribute:D $a, :$localized!) {
$a.set_build: -> \SELF, | {
$a.set_value: SELF, Proxy.new:
STORE => -> $, $val { say "store $val" },
FETCH => { say "fetch!"; 42 }
}
}
Run Code Online (Sandbox Code Playgroud)
然后,这将调用FETCH和STORE回调(请注意,FETCH由于内部原因(例如类型检查以及您直接看到的那些访问),可能会调用它们:
class C {
has $.attr is localized is rw;
}
my $c = C.new;
$c.attr = 'foo';
my $x = $c.attr;
Run Code Online (Sandbox Code Playgroud)
此示例说明了它也可以在类内部的属性读取中起作用:
class C {
has $.attr is localized is rw;
method m() {
$!attr = 'foo';
my $x = $!attr
}
}
C.new.m;
Run Code Online (Sandbox Code Playgroud)