使用特征应用代理

2024-04-14

我想为一个属性编写一个特征,为它提供一个代理,这样我就可以操纵 sees 背后的值,甚至可以为$!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";

虽然在这种情况下STORE方法被正确调用,但 fetch 方法未正确调用,其要点$foo.text is Scalar+{Localized}.new,这表明我没有完全正确地应用事物。


您需要安排Proxy to be bound到属性中,这样就有一个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 }
    }
}

然后这将调用FETCH and STORE回调(注意FETCH可能会因内部原因而被调用,例如类型检查以及您直接看到的访问):

class C {
    has $.attr is localized is rw;
}
my $c = C.new;
$c.attr = 'foo';
my $x = $c.attr;

此示例演示了它也可以在类内部的属性读取上起作用:

class C {
    has $.attr is localized is rw;

    method m() {
        $!attr = 'foo';
        my $x = $!attr
    }
}
C.new.m;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用特征应用代理 的相关文章

随机推荐