如何知道在使用 FALLBACK 时是否返回左值?
How to know if returning an l-value when using `FALLBACK`?
我如何知道在使用 FALLBACK
时我是否真的需要 return 左值?
我正在使用 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;
这感觉有点像 X-Y 问题,所以让我们简化示例,看看答案是否有助于您做出决定。
首先:如果您 return 散列中不存在的键的 "value",您实际上是在 returning 一个容器,它将自动激活分配给时哈希中的键:
my %hash;
sub get($key) { return-rw %hash{$key} }
get("foo") = 42;
dd %hash; # Hash %hash = {:foo(42)}
请注意,您需要在此处使用 return-rw
以确保实际容器被 returned,而不仅仅是容器中的值。或者,您可以使用 is raw
特性,它允许您只设置最后一个值:
my %hash;
sub get($key) is raw { %hash{$key} }
get("foo") = 42;
dd %hash; # Hash %hash = {:foo(42)}
请注意,在这种情况下,您应该不使用return
,因为它仍然会再次去容器化。
回到你的问题:
I want to track if I've actually modified %!attrs
or have only just read the value when FALLBACK
was called.
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
}
}
}
这将 return 在散列中找到的容器,或者记录对未知密钥的访问和 return 一个不可变的 Any
。
关于计划 B,记录更改:为此您可以使用 Proxy 对象。
希望这对您的探索有所帮助。
Liz 的回答充满了有用的信息,你已经接受了,但我认为以下内容可能仍然有用。
How to know if returning an l-value ... ?
让我们从忽略 FALLBACK
子句开始。
您必须测试该值。要处理Scalar
s,必须测试值的.VAR
。 (对于非 Scalar
值,.VAR
的行为类似于 "no op"。)我 认为 (但不要引用我的话)Scalar|Array|Hash
涵盖所有 l-value 超类型:
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
How to know if returning an l-value when using FALLBACK
?
添加 "when using FALLBACK
" 对答案没有影响。
How can I know if I actually need to return an l-value ... ?
同样,让我们从忽略 FALLBACK
子句开始。
这是一个与 "How to know if returning an l-value ... ?" 完全不同的问题。我认为这是你问题的核心。
Afaik,答案是,您需要预测 returned 值将如何使用。如果有 any 机会将它用作 l-value,并且您希望该用法有效,那么您需要 return 一个 l 值 。 language/compiler 不能(或至少不能)帮助您做出决定。
考虑一些相关场景:
my $baz := foo.bar;
... (100s of lines of code) ...
$baz = 42;
除非第一行 return 是 l 值 ,否则第二行将失败。
但实际情况比这更直接:
routine-foo = 42;
routine-foo
首先完整求值, 在 lhs = rhs
表达式求值之前 .
除非编译器对 routine-foo
调用的解析以某种方式包含了以下事实,即接下来发生的事情将是 lhs
将被分配给,否则将无法单独或多次分派 routine-foo
以了解它是否可以安全地 return 一个 r 值 或必须 return 一个 l 值.
并且编译器的解析不包含它。因此,例如:
multi term:<bar> is rw { ... }
multi term:<bar> { ... }
bar = 99; # Ambiguous call to 'term:<bar>(...)'
我可以想象这一天(N年后)通过允许=
成为可重载运算符、允许重载的健壮宏的组合来解决=
可用,并且例程解析被修改,因此上述不明确的调用可以做一些等同于解析到 is rw
multi 的事情。但我怀疑即使 N=10,它 实际上 也会通过。也许还有另一种方法,但我暂时想不出。
How can I know if I actually need to return an l-value when using FALLBACK
?
同样,添加 "when using FALLBACK
" 对答案没有影响。
I want to track if I've actually modified %!attrs
or have only just read the value when FALLBACK
was called.
当调用 FALLBACK
时,它不知道在什么上下文中调用它 -- r-value 或 l-value。在已经 returned.
之后进行任何修改
换句话说,无论你想出什么解决方案本身都与 FALLBACK
无关(即使你必须使用它来实现你正在尝试的任何其他方面)做)。
(即使是,我怀疑尝试通过 FALLBACK
本身来解决它只会让事情变得更糟 。可以想象写两个 FALLBACK
multis,一个具有 is rw
特征的,但是,如上所述,我的想象力并没有延伸到很快就会产生任何变化,如果有的话,并且只有在上述想象的事情发生时才会发生(宏等) .) and 编译器被 also 修改以注意两个 FALLBACK
multi 变体,我根本不是这个意思暗示这甚至是有道理的。)
B计划
Or (alternate plan B) can I attach a callback or something similar to my %!attrs
to monitor for changes?
正如 Lizmat 所说,那是 Proxy
的领域。因此你的下一个 SO 问题...... :)
我如何知道在使用 FALLBACK
时我是否真的需要 return 左值?
我正在使用 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;
这感觉有点像 X-Y 问题,所以让我们简化示例,看看答案是否有助于您做出决定。
首先:如果您 return 散列中不存在的键的 "value",您实际上是在 returning 一个容器,它将自动激活分配给时哈希中的键:
my %hash;
sub get($key) { return-rw %hash{$key} }
get("foo") = 42;
dd %hash; # Hash %hash = {:foo(42)}
请注意,您需要在此处使用 return-rw
以确保实际容器被 returned,而不仅仅是容器中的值。或者,您可以使用 is raw
特性,它允许您只设置最后一个值:
my %hash;
sub get($key) is raw { %hash{$key} }
get("foo") = 42;
dd %hash; # Hash %hash = {:foo(42)}
请注意,在这种情况下,您应该不使用return
,因为它仍然会再次去容器化。
回到你的问题:
I want to track if I've actually modified
%!attrs
or have only just read the value whenFALLBACK
was called.
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
}
}
}
这将 return 在散列中找到的容器,或者记录对未知密钥的访问和 return 一个不可变的 Any
。
关于计划 B,记录更改:为此您可以使用 Proxy 对象。
希望这对您的探索有所帮助。
Liz 的回答充满了有用的信息,你已经接受了,但我认为以下内容可能仍然有用。
How to know if returning an l-value ... ?
让我们从忽略 FALLBACK
子句开始。
您必须测试该值。要处理Scalar
s,必须测试值的.VAR
。 (对于非 Scalar
值,.VAR
的行为类似于 "no op"。)我 认为 (但不要引用我的话)Scalar|Array|Hash
涵盖所有 l-value 超类型:
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
How to know if returning an l-value when using
FALLBACK
?
添加 "when using FALLBACK
" 对答案没有影响。
How can I know if I actually need to return an l-value ... ?
同样,让我们从忽略 FALLBACK
子句开始。
这是一个与 "How to know if returning an l-value ... ?" 完全不同的问题。我认为这是你问题的核心。
Afaik,答案是,您需要预测 returned 值将如何使用。如果有 any 机会将它用作 l-value,并且您希望该用法有效,那么您需要 return 一个 l 值 。 language/compiler 不能(或至少不能)帮助您做出决定。
考虑一些相关场景:
my $baz := foo.bar;
... (100s of lines of code) ...
$baz = 42;
除非第一行 return 是 l 值 ,否则第二行将失败。
但实际情况比这更直接:
routine-foo = 42;
routine-foo
首先完整求值, 在 lhs = rhs
表达式求值之前 .
除非编译器对 routine-foo
调用的解析以某种方式包含了以下事实,即接下来发生的事情将是 lhs
将被分配给,否则将无法单独或多次分派 routine-foo
以了解它是否可以安全地 return 一个 r 值 或必须 return 一个 l 值.
并且编译器的解析不包含它。因此,例如:
multi term:<bar> is rw { ... }
multi term:<bar> { ... }
bar = 99; # Ambiguous call to 'term:<bar>(...)'
我可以想象这一天(N年后)通过允许=
成为可重载运算符、允许重载的健壮宏的组合来解决=
可用,并且例程解析被修改,因此上述不明确的调用可以做一些等同于解析到 is rw
multi 的事情。但我怀疑即使 N=10,它 实际上 也会通过。也许还有另一种方法,但我暂时想不出。
How can I know if I actually need to return an l-value when using
FALLBACK
?
同样,添加 "when using FALLBACK
" 对答案没有影响。
I want to track if I've actually modified
%!attrs
or have only just read the value whenFALLBACK
was called.
当调用 FALLBACK
时,它不知道在什么上下文中调用它 -- r-value 或 l-value。在已经 returned.
换句话说,无论你想出什么解决方案本身都与 FALLBACK
无关(即使你必须使用它来实现你正在尝试的任何其他方面)做)。
(即使是,我怀疑尝试通过 FALLBACK
本身来解决它只会让事情变得更糟 。可以想象写两个 FALLBACK
multis,一个具有 is rw
特征的,但是,如上所述,我的想象力并没有延伸到很快就会产生任何变化,如果有的话,并且只有在上述想象的事情发生时才会发生(宏等) .) and 编译器被 also 修改以注意两个 FALLBACK
multi 变体,我根本不是这个意思暗示这甚至是有道理的。)
B计划
Or (alternate plan B) can I attach a callback or something similar to my
%!attrs
to monitor for changes?
正如 Lizmat 所说,那是 Proxy
的领域。因此你的下一个 SO 问题...... :)