如何知道使用`FALLBACK`时是否返回左值?

gdo*_*ald 6 metaprogramming lvalue perl6 raku

我怎么知道使用时我是否真的需要返回l值FALLBACK

我正在使用,return-rw但我只想return在可能的地方使用。我想跟踪我是否实际上已修改过%!attrs或仅在FALLBACK调用时读取了该值。

或者(替代方案B)我可以附加回调或类似的东西%!attrs来监视更改吗?

class Foo {
  has %.attrs;
  submethod BUILD { %!attrs{'bar'} = 'bar' }

#  multi method FALLBACK(Str:D $name, *@rest) {
#    say 'read-only';
#    return %!attrs{$name} if %!attrs«$name»:exists;
#  }

  multi method FALLBACK(Str:D $name, *@rest) {
    say 'read-write';
    return-rw %!attrs{$name} if %!attrs«$name»:exists;
  }
}

my $foo = Foo.new;
say $foo.bar;

$foo.bar = 'baz';
say $foo.bar;
Run Code Online (Sandbox Code Playgroud)

Eli*_*sen 7

这感觉有点像XY问题,因此让我们简化示例,看看该答案是否对您的决策有所帮助。

首先:如果您在哈希中返回不存在的键的“值”,那么实际上您将返回一个容器,当分配给以下容器时,该容器将自动激活哈希中的键:

my %hash;
sub get($key) { return-rw %hash{$key} }
get("foo") = 42;
dd %hash;   # Hash %hash = {:foo(42)}
Run Code Online (Sandbox Code Playgroud)

请注意,您需要在return-rw此处使用以确保返回实际的容器,而不仅仅是返回容器中的值。或者,您可以使用is raw特征,它允许您仅设置最后一个值:

my %hash;
sub get($key) is raw { %hash{$key} }
get("foo") = 42;
dd %hash;   # Hash %hash = {:foo(42)}
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,请勿使用return,因为那样仍会再次去除容器内的污染物。

回到您的问题:

我想跟踪我是否实际上已修改过%!attrs或仅在FALLBACK调用时读取了该值。

class Foo {
    has %!attrs;
    has %!unexpected;

    method TWEAK() { %!attrs<bar> = 'bar' }

    method FALLBACK(Str:D $name, *@rest) is raw {
        if %!attrs{$name}:exists {
            %!attrs{$name}
        }
        else {
            %!unexpected{$name}++;
            Any
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将返回在哈希中找到的容器,或者记录对未知键的访问并返回一个不可变的Any

关于计划B,记录更改:为此,您可以为此使用Proxy对象。

希望这对您的追求有所帮助。