在 ruby 中处理嵌套条件的最佳方法是什么?

What is the best way to handle nested conditionals in ruby?

我有以下逻辑:

if something
  some_variable = true if another_variable
  your_variable = true if that_other_variable
elsif thatthing
  my_variable = true if another_variable
  her_variable = true if that_other variable
else
  puts "nothing found"
end

这是极其简化的逻辑。请提前原谅变量的名称。

来自另一种语言,我习惯于认为嵌套内联如果出于可读性原因的条件不好。我也对真实性类型测试有偏见。我尽量避免否定,但有时这是不可避免的。

也就是说,我有几种常见的可能性可以用来替换内联 if,还有一种比较不常见的可能性,我将它们放在一起以避免否定。我正在寻找反馈,以及您正在做的一些事情来解决这个问题。开始了:

可能性 1:

三元:

if something
  some_variable = defined?(another_variable) ? true : false

可能性2:

否定:

if something
  some_variable = !defined?(another_variable)
# There are some variations to this, but this helps to address the negation I am trying to avoid.

可能性3(我更喜欢这个,但似乎有点不常见):

if something
  some_variable = (defined?(another_variable) && another_variable.length > 0)    # Two truth based tests (does the var exist, and is it greater than 0 in length) This returns true/false.

请让我知道是否有人有任何其他解决方案,以及他们认为最惯用的解决方案。

谢谢!

您不需要 true if <var> 部分,可以使用 !! 代替:

if something
  some_variable = !!another_variable
  your_variable = !!that_other_variable
elsif thatthing
  my_variable  = !!another_variable
  her_variable = !!that_other variable
else
  puts "nothing found"
end

好吧,我不会试图在评论中塞满我的答案,我会给出一个答案,即使它不完全是 "answer"。

您的所有备选方案都不相同,它们都做不同的事情。你到底想做什么?

 some_variable = true if another_variable

仅当 another_variable 具有真值时才会设置 some_variable = true。在 ruby 中,除 nilfalse 之外的任何值在布尔测试中都被评估为 true。 another_variable 必须已经存在,否则会引发异常。

  • 因此,如果 another_variable 存在,并且不是 nilfalse,您将设置 some_variable 为真。
  • 如果 another_variable 存在并且是 nilfalse,您根本不会更改 some_variable 的值,它将保持不变。它将不会设置为false。 (如果 some_variable 不存在,它 nil 值存在。否则它的先前值将保持不变)。
  • 如果 another_variable 根本不存在,该语句将引发异常。

这是你的意图吗? (顺便说一句,使用这些无意义的变量名会使谈论您的示例更加混乱)。

如果这真的是您想要的(而且我怀疑它是否如此),那么可能没有比您已经完成的方式更短或更清晰的方式来做到这一点:some_variable = true if another_variable

ruby 中的单行尾随 if 并没有什么不惯用的地方,它非常地道,人们总是这样做,因为它使代码更清晰。在你的例子中——同样很难从你的假例子中分辨出来——我不认为这是一条线,如果这使得很难说出发生了什么,这是顶级条件的奇怪结构,代码本身的整体结构,很难说出它到底应该做什么。但是你说你不想重构它,那好吧。也许这只是你试图产生一个简单的假设并提出一个非常令人困惑的假设的产物,也许原始代码并不那么令人困惑。

您的其他替代示例其他,它们并不等效。例如:

some_variable = defined?(another_variable) ? true : false

这与您的第一个示例具有不同的语义。

  • 如果 another_variable 存在 ,则 some_variable 将被设置为真。即使 another_variable 存在且值为 nilfalse。只要 another_variable 存在,some_variable 就会被设置为 true。
  • 如果 another_variable 根本不存在 some_variable 将被设置为 false。
  • 没有 some_variable 不会被触动的情况。

如果那是您真正想要做的,那么肯定有更简洁的选择。 defined? returns 如果未定义变量则为 nil,否则为解释已定义变量性质的字符串。如果你想把它变成严格的布尔值 truefalse,你可以使用双重布尔值取反:some_variable = !! defined?(another_variable)。回想一下,在 ruby 中,除了 falsenil 之外的任何东西在布尔上下文中都被评估为真值,因此 !! foo 将变成 false 如果 foonilfalse,如果 foo 是其他任何东西,则 true

人们通常也只是做 some_variable = defined?(another_variable) 并且认为这足以捕获 "did another_variable exist",因为 some_variable 在布尔测试中仍然会被评估为相同的值。虽然实际上,在惯用的 ruby 中你只是偶尔需要 defined? ,但大多数情况下你正在使用你已经知道存在的变量,你不需要测试它们是否存在,甚至更多您很少需要将该测试的结果存储在变量中。

您的其他示例又有不同的语义,其中 none 实际上是等价的。希望我在这里为您提供了工具,让您了解它们的实际作用。您还可以在一个小测试脚本或 irb REPL 中尝试所有这些。

我怀疑这些都不是您真正想要做的。这取决于您没有告诉我们的实际语义。如果您开始使用的第一个版本确实代表了您想要的语义,那么我认为没有更短的方法可以做到这一点。

你说你在重构现有的代码 -- 根据你给我们的这个例子,我认为现有的代码可能很乱,里面有很多错误,写得很奇怪,而且不确定是什么甚至 应该 这样做,因为您不是原始开发人员。我猜它也没有任何测试。在这种情况下,我会先编写一些测试来确定代码 应该 做什么,然后您可以尝试重构并确保它仍然按预期执行。如果没有它,并且代码如此混乱,尤其是 ruby 是新手,您的重构很可能会在您不打算更改程序的语义时更改程序的语义,可能会引入新的甚至更奇怪的错误。