问题描述
在 kotlin 和 C# 中,您可以分配一个变量,否则如果值为 nil,您可以使用 ?:
和 ??
运算符抛出异常。
例如,在 C# 中:
var targetUrl = GetA() ?? throw new Exception("Missing A");
// alt
var targetUrl = GetA() ?? GetB() ?? throw new Exception("Missing A or B");
这在 ruby 中可行吗?如果是这样,如何?
基本上,我想做的是这个
target_url = @maybe_a || @maybe_b || raise "either a or b must be assigned"
我知道我可以做到这一点
target_url = @maybe_a || @maybe_b
raise "either a or b must be assigned" unless target_url
但如果可能的话,我想在一行中完成
解决方法
基本上,我想做的是这个
target_url = @maybe_a || @maybe_b || raise "either a or b must be assigned"
您必须为 raise
添加括号才能使您的代码正常工作:
x = a || b || raise("either a or b must be assigned")
使用控制流运算符 or
而不是 ||
会“更正确”:(这使得括号可选)
x = a || b or raise "either a or b must be assigned"
这是 Perl 的“do this or die” 成语,我认为它干净整洁。它强调了一个事实,即 raise
不为 x
提供结果 - 它只是因其副作用而被调用。
然而,有些人认为 or
/ and
令人困惑,根本不应该使用。 (见rubystyle.guide/#no-and-or-or)
Rails 大量使用的一种模式是有两种方法,一种没有 !
,它不提供错误处理:
def a_or_b
@maybe_a || @maybe_b
end
和一个带有 !
的函数:
def a_or_b!
a_or_b || raise("either a or b must be assigned")
end
然后通过以下方式调用它:
target_url = a_or_b!
,
你可以用括号解决它:
(target_url = @maybe_a || @maybe_b) || raise("either a or b must be assigned")
,
使用运算符优先级
另一种以极少的代码更改完成您想要的操作的方法是使用 lower-precedence or
运算符,它的优先级低于 ||
和 =
.例如:
# This is closest to what you want,but violates many style guides.
target_url = @maybe_a || @maybe_b or raise "either a or b must be assigned"
您还可以在不改变其工作方式的情况下包装逻辑行,例如:
# Same code as above,but wrapped for line length
# and to clarify & separate its expressions.
target_url = @maybe_a || @maybe_b or
raise "either a or b must be assigned"
无论哪种方式,代码都会按预期引发 RuntimeError 异常。由于优先规则,不需要括号。
请注意,许多 style guides like this one 会告诉您完全避免使用 or
运算符,或者仅将其用于流量控制,因为它通常是导致细微优先级错误的原因一目了然。话虽如此,包装版本实际上只是 my other answer 的倒置变体,并且在不使用括号的情况下很容易在视觉上区分,尤其是启用了语法突出显示。您的里程和风格指南的严格程度肯定会有所不同。
在赋值表达式中使用后缀条件
因为 Ruby 中的大部分内容都计算为一个表达式,您可以通过使用 unless
作为后缀条件后跟一个赋值表达式来将其作为单个逻辑行执行。我选择将线包裹起来以适应合理的线长,但如果您真的想要“单线”,请随意将其设为单线。例如:
raise "either a or b must be assigned" unless
target_url = @maybe_a || @maybe_b
如您所料,这将正确引发 RuntimeError。
自动激活
请注意,这种特殊方法会自动激活 @maybe_a 并为其分配 nil
。如果 @maybe_a 评估为 false,它也会对 @maybe_b 做同样的事情。虽然很方便,但如果您依赖 defined? 来识别代码中其他地方的未定义变量,自动激活可能会在以后绊倒您。因此,这个习语的优缺点取决于你更广泛的意图,但它肯定会在原始问题的范围内完成工作。