Ruby 分配一个变量或在 nil 时引发错误

Posted

技术标签:

【中文标题】Ruby 分配一个变量或在 nil 时引发错误【英文标题】:Ruby assign a variable or raise error if nil 【发布时间】:2021-05-25 07:28:11 【问题描述】:

在 kotlin 和 C# 中,您可以分配一个变量,否则如果值为 nil,您可以使用 ?:?? 运算符引发异常。

例如,在 C# 中:

var targetUrl = GetA() ?? throw new Exception("Missing A");
// alt
var targetUrl = GetA() ?? GetB() ?? throw new Exception("Missing A or B");

这在红宝石中可能吗?如果有,怎么做?

基本上,我想做的就是这个

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

但如果可能的话,我想在一行中完成

【问题讨论】:

【参考方案1】:

基本上,我想做的就是这个

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!

【讨论】:

谢谢!我没有意识到它就像在raise 的参数周围需要括号一样简单。非常感谢【参考方案2】:

使用运算符优先级

另一种通过极少的代码更改来完成您想要的操作的方法是使用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 的反转变体,并且在不使用括号的情况下很容易在视觉上区分,尤其是在启用语法突出显示的情况下。您的里程和风格指南的严格程度肯定会有所不同。

【讨论】:

【参考方案3】:

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

因为 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? 来识别代码中其他地方的未定义变量,那么自动激活可能会在以后绊倒您。因此,这个习语的优缺点取决于你更广泛的意图,但它肯定会在原始问题的范围内完成工作。

【讨论】:

【参考方案4】:

你可以用括号来解决它:

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

【讨论】:

以上是关于Ruby 分配一个变量或在 nil 时引发错误的主要内容,如果未能解决你的问题,请参考以下文章

为啥此 C# 代码会引发错误:使用未分配的局部变量 'n'

发现可选值错误 nil swift 3

如何在使用“ls”命令以及将输出分配给变量时抑制标准错误?

Error-ASP.NET:由于未能找到 id 为“FileUpload1$gvFiles$ctl02$lnkBtnRemoveFile”的控件或在回发后将同一 ID 分配给另一个控件,导致发生错误。

IBOutlet 变量在我尝试访问它们时返回 nil。错误:线程 1:致命错误:在展开可选值时意外发现 nil

将 Delegate 分配给 PopoverPresentationController 时出现 Nil 错误