Liz 的回答充满了有用的信息,您已经接受了,但我认为以下内容可能仍然令人感兴趣。
如何知道是否返回左值...?
让我们先忽略FALLBACK 子句。
您必须测试该值。处理Scalars,必须测试.VAR的值。 (对于非Scalar 值,.VAR 就像“无操作”。)我认为(但不要引用我的话)Scalar|Array|Hash 涵盖了所有 l-值 超类型:
my \value = 42; # Int is an l-value is False
my \l-value-one = $; # Scalar is an l-value is True
my \l-value-too = @; # Array is an l-value is True
say "{.VAR.^name} is an l-value is {.VAR ~~ Scalar|Array|Hash}"
for value, l-value-one, l-value-too
使用FALLBACK时如何知道是否返回左值?
添加“使用FALLBACK时”对答案没有影响。
我怎么知道我是否真的需要返回一个l-value ...?
再次,让我们先忽略FALLBACK 子句。
这是一个与“如何知道是否返回左值...?”完全不同的问题。我认为这是您问题的核心。
Afaik,答案是,您需要预测返回值将如何使用。如果有任何机会将其用作l-value,并且您希望该用法起作用,那么您需要返回一个l-value。语言/编译器不能(或至少不能)帮助您做出决定。
考虑一些相关场景:
my $baz := foo.bar;
... (100s of lines of code) ...
$baz = 42;
除非第一行返回一个l-value,否则第二行将失败。
但情况实际上比这更直接:
routine-foo = 42;
首先评估routine-foo,在评估lhs = rhs 表达式之前。
除非编译器对 routine-foo 调用的解析以某种方式结合了这样一个事实,即接下来发生的事情就是将分配给 lhs,否则将无法单独或多次调度 @987654338 @ 知道它是否可以安全地返回一个 r-value 或必须返回一个 l-value。
而编译器的分辨率并没有 包含这一点。因此,例如:
multi term:<bar> is rw { ... }
multi term:<bar> { ... }
bar = 99; # Ambiguous call to 'term:<bar>(...)'
我可以想象这一天(从现在起 N 年后)通过允许 = 成为可重载运算符、允许重载 = 可用的健壮宏的组合来解决,并修改了例程解析,因此上述模棱两可的调用可以做相当于解析is rw multi的事情。但我怀疑即使 N=10,它实际上也会通过。也许还有另一种方法,但我现在想不出。
在使用FALLBACK时,我如何知道我是否真的需要返回一个左值 ?
同样,添加“使用FALLBACK 时”对答案没有影响。
我想跟踪我是否真的修改了%!attrs,或者只是在调用FALLBACK 时读取了值。
当FALLBACK 被调用时,它不知道它在什么上下文中被调用 -- r-value 或 l-value。任何修改都是在它已经返回之后进行的。
换句话说,无论你想出什么解决方案本身都与FALLBACK 无关(即使你必须使用它来实现你正在尝试做的任何其他方面)。
(即使是这样,我怀疑尝试通过 FALLBACK 本身解决它只会使问题更糟。可以想象编写两个 FALLBACK multis,一个具有 is rw trait ,但是,如上所述,我的想象力并没有延伸到任何时候,如果有的话,很快就会产生任何影响,并且只有当上述想象的事情发生(宏等)和时才会发生编译器也被修改以注意两个FALLBACK multi 变体,我完全没有意思暗示这甚至是有道理的。)
B计划
或者(备选方案 B)我可以附加回调或类似于我的%!attrs 的内容来监控更改吗?
正如 Lizmat 所说,这是Proxys 的领域。因此,您的下一个 SO 问题... :)