如果不是 Nil,则变量重新分配方法结果
Posted
技术标签:
【中文标题】如果不是 Nil,则变量重新分配方法结果【英文标题】:Variable re-assign method result if not Nil 【发布时间】:2021-10-06 08:08:00 【问题描述】:是否有应用和分配对象变量方法调用的惯用方式,但前提是它已定义(方法和结果)?
喜欢使用safe call operator .?
和defined-or operator //
,并遵循“DRY 原则”——在操作中只使用一次变量?
像这样(但使用另一个变量感觉像是在作弊):
my $nicevariable = "fobar";
# key step
(my $x := $nicevariable) = $x.?possibly-nonexistent-meth // $x;
say $nicevariable; # => possibly-nonexistent-meth (non-Nil) result or "foobar"
...如果可能的话,避免andthen
。
【问题讨论】:
【参考方案1】:假设该方法返回 定义的内容,您可以这样做(如果我正确理解了这个问题):
my $x = "foobar";
$x = $_ with $y.?possibly-nonexistent-meth;
$x
如果方法不存在(或者它确实存在并返回一个类型对象)将保持不变。
【讨论】:
(你的意思可能是$x
而不是$y
。)
有趣。我还没有得到,它是如何通过我的非 Nil 条件的......
.. 可能是根据定义 :) (with
名称不是很具描述性)
如果我不想覆盖变量并在关键行中只“提及”一次,那可能是正确的选择。
@mykhal re $y
vs $x
:你告诉我 :-) 从示例代码中我并不清楚。【参考方案2】:
我不完全确定“在操作中仅使用一次变量”是什么意思。如果 Liz 的答案符合条件,那么这可能是更清洁的方法。
如果不是,这里有一种不同的方法,可以避免两次命名变量:
my $nicevariable = "foobar";
$nicevariable.=&.^lookup('possibly-nonexistent-meth')($_)
这对我来说有点太神秘了;它的作用是:如果该方法存在,则类似于¹调用&method($nicevariable)
,与$nicevariable.method
相同。如果该方法确实不存在,那么它就像调用Mu($nicevariable)
- 即将$nicevariable
强制转换为Mu
或Mu
的子类型。但是由于一切都已经是Mu
的子类型,所以这是一个空操作,只返回$nicevariable
。
[1]:不完全是,因为&method
将是一个 Sub,但基本上。
编辑:
实际上,这太复杂了。这是一个更简单的版本:
my $nicevariable = "foobar";
$nicevariable.=&.?possibly-nonexistent-meth // $_
不知道为什么我一开始就没有这个……
【讨论】:
编辑非常接近我的意思...我在玩.=
,但我没有想到&
的把戏,谢谢。【参考方案3】:
你知道变量上的default trait吗?
不确定它是否适合您的用例,但 $some-var.?unknown-method
返回 Nil,所以:
my $nicevariable is default("fobar");
$nicevariable = $nicevariable.?possibly-nonexistent-meth;
say $nicevariable; # fobar
导致$nicevariable
被重置为其默认值;
【讨论】:
【参考方案4】:截至this merge,您可以写:
try let $foo .= bar
这比我认为的理想解决方案差了一步,不幸的是,这是一个语法错误(由于 Raku 的 当前 语法普遍存在弱点,我猜这实际上是无法解决的,尽管我很想解决它):
let $foo .?= bar # Malformed postfix call...
(也许我在想象一些事情,但我看到了一丝希望,即上述皱纹(以及许多人喜欢的皱纹)会在几年后被抚平。这将是在 RakuAST 登陆 Raku .e
之后,并且希望在 Raku .f
或 .g
中清理语法。)
您的问题的标题是:
如果不是
Nil
,则变量重新分配方法结果
如果不是undefined,我的解决方案会执行变量重新分配方法,这比Nil
更通用。
然后,您的问题的 正文 要求正是更通用的解决方案:
是否有应用和分配对象变量方法调用的惯用方式,但前提是它已定义(方法和结果)?
那么我的解决方案是否理想?
我的解决方案不是惯用的。但这很可能是因为我发现的错误,现在通过我的答案开头链接的合并解决了。我看不出它为什么不应该成为惯用语,一旦它在运送 Rakudos。
潜在的大问题是try
存储$!
中抛出的任何异常,而不是让它爆炸。对于给定的用例,也许这没问题;也许不是。
特别感谢您提出问题,这促使我们提出了各种解决方案,这导致我提出问题,这导致 vrurg 分析我遇到的问题然后修复它。 :)
【讨论】:
我喜欢这个版本——尤其是因为您仍然可以访问$!
中的任何解除异常/故障,这可以保留您处理某些问题的选择权。
请注意,根据.bar
方法的内容,您无法保证$foo
实际上会保持不变,即使发生了一些异常。
@ElizabethMattijsen 我知道有些方法可能会开始改变它们的调用者然后抛出,或者先抛出然后.resume
,但我认为你不是那个意思(这将是代码节答案的问题也)。我对在抛出异常时退出执行语句的确切细节感到模糊,但听到try
无法立即退出分配或绑定语句(let
或任何其他)让我感到惊讶如果在评估 rhs 时抛出异常。如果这就是你的意思,你能链接到我能读到的东西吗? TIA。
@raiph 我不确定你能读到什么。赋值实际上与在对象中设置属性没有什么不同。如果这发生在执行错误之前,它将保持设置。除非您有一个 UNDO 移相器来撤消该设置。这能回答你的问题吗?
@ElizabethMattijsen “分配实际上与在对象中设置属性没有什么不同。”正确的。 “如果在执行错误之前发生这种情况,它将保持不变。”甚至是let
?!?考虑my Int @array = 1, 2; try let @array = (42 and die) ; try let @array = 3, 'a' ; .say for $!, @array; # Type check failed in assignment ... got Str ("a")[1 2]
。第一个try
在评估let
的右轴时抛出。第二次抛出在分配let
的lhs。然而 both 情况的最终结果是 @array
保持不变。我错过了什么场景?以上是关于如果不是 Nil,则变量重新分配方法结果的主要内容,如果未能解决你的问题,请参考以下文章