Ruby 分配一个变量或如果为 nil 则引发错误

Ruby assign a variable or raise error if nil

在 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")

在赋值表达式中使用后缀条件

因为 Ruby 中的大部分内容都计算为表达式,您可以通过使用 unless 作为后缀条件后跟赋值表达式来将其作为单个逻辑行来执行。我选择将线换行以适合合理的线长,但如果您真的想要“单线”,请随意将其设为单线。例如:

raise "either a or b must be assigned" unless
  target_url = @maybe_a || @maybe_b

如您所料,这将正确引发 RuntimeError。

自动复活

请注意,此特定方法将自动激活 @maybe_a 并为其分配 nil。如果 @maybe_a 评估为错误,它也会对 @maybe_b 执行相同的操作。虽然方便,但如果您依赖 defined? 来识别代码中其他地方的未定义变量,自动激活可能会在以后绊倒您。因此,这个成语的优缺点将取决于你更广泛的意图,但它肯定会在原始问题的范围内完成工作。

使用运算符优先级

另一种只需极少更改代码即可完成所需操作的方法是使用 lower-precedence or 运算符,它的优先级低于 || 和 [=14] =].例如:

# 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 will tell you to avoid the or operator altogether, or to use it only for flow control, because it is often the cause of subtle precedence bugs that can be hard to spot at a glance. With that said, the wrapped version is really just an inverted variation of 的数量,并且在不使用括号的情况下很容易从视觉上区分,尤其是在启用语法突出显示的情况下。您的里程数和风格指南的严格程度肯定会有所不同。

Basically, what I want to do is this

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 的 “不做就死” 我认为干净整洁的成语。它强调了 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!