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

时间:2022-06-18 22:43:06

I have the following logic:

我的逻辑如下:

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

This is extremely simplified logic. Please forgive in advance for the names of the vars.

这是极其简化的逻辑。请先原谅我把vars的名字弄错了。

Coming from another language, I have conditioned my mind to think that nested inline if conditions are bad for readability reasons. I also have biases towards truthiness type tests. I tried to avoid negation if possible, but some times its unavoidable.

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

That being said, I have a couple of common possibilities of what I could use to replace the inline ifs, and one that is more uncommon that I put together to avoid negation. I am looking for feedback, and some things that you are doing to address this. Here it goes:

也就是说,我有一些常见的可能性可以用来替换内联ifs,还有一种更不常见的可能性是为了避免否定。我在寻找反馈,以及你正在做的一些事情来解决这个问题。这里是:

Possibility 1:

可能性1:

ternary:

三元:

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

Possibility 2:

可能性2:

negation:

否定:

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.

Possibility 3 (I am favoring this one, but it seems a little uncommon):

可能性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.

Please let me know if anyone has any other solutions, and also which they feel is the most idiomatic.

如果有人有其他的解决方案,请告诉我,而且他们觉得这是最地道的。

Thank you!

谢谢你!

2 个解决方案

#1


4  

Okay, instead of trying to stuff my answers in comments, I'll just give an answer, even though it's not quite an "answer".

好吧,与其把我的答案写在评论里,我只给出一个答案,即使它不是一个“答案”。

All of your alternatives are not equivalent, they all do different things. What are you actually trying to do?

你所有的选择都不是等同的,他们都做不同的事情。你到底想做什么?

 some_variable = true if another_variable

Will set some_variable = true only if another_variable has a truthy value. In ruby, any value but nil or false is evaluated as true in a boolean test. another_variable has to already exist, otherwise you'll get an exception raised.

将设置some_variable = true,仅当另一个变量具有真实值时。在ruby中,除了nil或false之外的任何值都将在布尔测试中作为true进行计算。another_variable必须已经存在,否则会引发异常。

  • So if another_variable exists, and is anything but nil or false, you'll set some_variable to true.
  • 因此,如果存在一个other_variable,而且它不是nil或false,那么您将把some_variable设置为true。
  • If another_variable exists and is nil or false, you won't change the value of some_variable at all, it will remain unchanged. It will not be set to false. (if some_variable didn't already exist, it will be brought into existence with a nil value. Otherwise it's previous value will be unchanged).
  • 如果存在一个other_variable,并且为nil或false,那么您根本不会更改some_variable的值,它将保持不变。它不会被设置为false。(如果some_variable尚未存在,它将以nil值引入。否则它的先前值将保持不变)。
  • If another_variable didn't exist at all, the statement will raise an exception.
  • 如果一个other_variable根本不存在,该语句将引发一个异常。

Is that what you intend? (And incidentally, using these meaningless variable names makes it a lot more confusing to talk about your example).

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

If that's really what you intend (and I'm doubting that it is), then there's probably no shorter or clearer way to do it than the way you've done: some_variable = true if another_variable.

如果这确实是您想要的(我对此表示怀疑),那么可能没有比您所做的方式更短或更清楚的方法了:some_variable = true If another_variable。

There's nothing un-idiomatic with a one-line trailing if in ruby, it's perfectly idiomatic, people do it all the time, when it makes the code more clear. In your example -- and again it's hard to tell from your fake example -- I don't think it's the one-line if that makes it hard to tell what's going on, it is the weird structure of the top-level conditions, the overall structure of the code itself, it's very difficult to tell what the heck it's supposed to be doing. But you say you don't want to refactor that, so okay. And maybe that's just an artifact of you trying to produce a simple hypothetical and coming up with an awfully confusing one, maybe the original code isn't as confusing.

如果在ruby中有一行结尾,没有什么不符合习惯的,这是完全符合习惯的,人们总是这么做,当它使代码更清晰的时候。在你的例子中,又很难告诉你假的例子——我不认为这是很难的一行如果告诉发生了什么,这是*的奇怪的结构条件下,代码本身的整体结构,很难告诉到底是应该做的。但是你说你不想重构它,好吧。也许这只是你试图提出一个简单的假设然后提出一个非常令人困惑的假设,也许原始代码没有那么令人困惑。

Your other alternative examples do something else, they are not equivalent. For instance:

你的其他例子做了其他的事情,它们是不相等的。例如:

some_variable = defined?(another_variable) ? true : false

This has different semantics than your first example.

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

  • if another_variable exists at all, then some_variable will be set to true. Even if another_variable exists with the value nil or false. So long as another_variable exists, some_variable will be set to true.
  • 如果存在一个other_variable,那么some_variable将被设置为true。即使another_variable存在值为nil或false。只要存在一个other_variable, some_variable将被设置为true。
  • If another_variable does not exist at all some_variable will be set to false.
  • 如果一个other_variable根本不存在,那么some_variable将被设置为false。
  • There is no case where some_variable will be untouched.
  • 在任何情况下,some_variable都不会被修改。

If that's really what you intend to do, then there certainly is a more concise alternative. defined? returns nil if the variable is not defined, otherwise a string explaining the nature of the defined variable. If you want to turn that into strictly boolean true or false, you can use a double boolean negation: some_variable = !! defined?(another_variable). Recall that in ruby anything but false or nil is evaluated as truthy in a boolean context, so !! foo will turn into false if foo was nil or false, and true if foo was anything else.

如果这是你真正想做的,那么肯定有一个更简洁的选择。定义?如果变量未定义,则返回nil,否则将返回解释已定义变量性质的字符串。如果您想将其转换为严格的布尔真或假,您可以使用双布尔否定:some_variable = !定义?(another_variable)。回想一下,在ruby中,除了false或nil之外的任何东西都在布尔上下文中被当作是真实的,所以!如果foo是nil或false, foo就会变成false,如果foo是别的东西,就变成true。

People also just commonly do some_variable = defined?(another_variable) and figure that's good enough to capture "did another_variable exist", since some_variable will still be evaluated the same in a boolean test. Although really, in idiomatic ruby you only occasionally need defined? at all, mostly you are working with variables you already know exist, and you don't need to test to see if they do, and even more seldom do you need to store the results of that test in a variable.

人们通常也会做some_variable = defined?(another_variable)和图,这就足够好了,可以获取“another_variable存在”,因为some_variable在布尔测试中仍然会得到相同的评价。尽管如此,在惯用的ruby中,您偶尔只需要定义?总之,大多数情况下,您使用的是您已经知道的变量,您不需要进行测试来查看它们是否存在,甚至您很少需要将该测试的结果存储在一个变量中。

Your additional examples all have yet different semantics again, none of them are actually equivalent. Hopefully I've given you the tools here to see what they all actually do. You can also try them all out in a little test script, or in the irb REPL.

您的额外示例都有不同的语义,它们实际上都不是等价的。希望我已经给了你们这些工具来看看它们的实际作用。您还可以在一个小测试脚本或irb REPL中尝试所有这些。

I suspect neither of these are what you actually want to do. It depends on the actual semantics you want, which you haven't told us. If your first version you start out with actually does represent the semantics you want, then I think there's no shorter way to do it.

我猜这两个都不是你真正想做的。它取决于你想要的实际语义,你还没有告诉我们。如果你的第一个版本确实代表了你想要的语义,那么我认为没有更短的方法。

You say you are refactoring existing code -- Based on this example you give us, I think the existing code may likely be a mess, with lots of bugs in it, written strangely, and with lack of certainty about what it's even supposed to do, since you aren't the original developer. I'm guessing it doesn't have any tests either. In this situation, I'd start by writing some tests establishing what the code is supposed to do, and then you can try refactoring and make sure it still performs as expected. Without that, and with such messy code, and especially with being newish to ruby, your refactoring is highly likely to change the semantics of the program when you weren't intending to, likely introducing new and even stranger bugs.

你说你是重构现有代码——根据你这个例子给我们,我认为现有的代码可能会一团糟,有很多错误,写奇怪的是,和缺乏确定性甚至应该做什么,因为你不是最初的开发人员。我猜它也没有任何测试。在这种情况下,我将首先编写一些测试来确定代码应该做什么,然后您可以尝试重构并确保它仍然按预期执行。如果没有这些,而且代码也很混乱,尤其是ruby还不成熟,重构很可能会在你不希望的情况下改变程序的语义,可能会引入新的甚至更奇怪的bug。

#2


2  

You don't need that true if <var> part and can use !!instead:

如果部分可以使用!!

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

#1


4  

Okay, instead of trying to stuff my answers in comments, I'll just give an answer, even though it's not quite an "answer".

好吧,与其把我的答案写在评论里,我只给出一个答案,即使它不是一个“答案”。

All of your alternatives are not equivalent, they all do different things. What are you actually trying to do?

你所有的选择都不是等同的,他们都做不同的事情。你到底想做什么?

 some_variable = true if another_variable

Will set some_variable = true only if another_variable has a truthy value. In ruby, any value but nil or false is evaluated as true in a boolean test. another_variable has to already exist, otherwise you'll get an exception raised.

将设置some_variable = true,仅当另一个变量具有真实值时。在ruby中,除了nil或false之外的任何值都将在布尔测试中作为true进行计算。another_variable必须已经存在,否则会引发异常。

  • So if another_variable exists, and is anything but nil or false, you'll set some_variable to true.
  • 因此,如果存在一个other_variable,而且它不是nil或false,那么您将把some_variable设置为true。
  • If another_variable exists and is nil or false, you won't change the value of some_variable at all, it will remain unchanged. It will not be set to false. (if some_variable didn't already exist, it will be brought into existence with a nil value. Otherwise it's previous value will be unchanged).
  • 如果存在一个other_variable,并且为nil或false,那么您根本不会更改some_variable的值,它将保持不变。它不会被设置为false。(如果some_variable尚未存在,它将以nil值引入。否则它的先前值将保持不变)。
  • If another_variable didn't exist at all, the statement will raise an exception.
  • 如果一个other_variable根本不存在,该语句将引发一个异常。

Is that what you intend? (And incidentally, using these meaningless variable names makes it a lot more confusing to talk about your example).

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

If that's really what you intend (and I'm doubting that it is), then there's probably no shorter or clearer way to do it than the way you've done: some_variable = true if another_variable.

如果这确实是您想要的(我对此表示怀疑),那么可能没有比您所做的方式更短或更清楚的方法了:some_variable = true If another_variable。

There's nothing un-idiomatic with a one-line trailing if in ruby, it's perfectly idiomatic, people do it all the time, when it makes the code more clear. In your example -- and again it's hard to tell from your fake example -- I don't think it's the one-line if that makes it hard to tell what's going on, it is the weird structure of the top-level conditions, the overall structure of the code itself, it's very difficult to tell what the heck it's supposed to be doing. But you say you don't want to refactor that, so okay. And maybe that's just an artifact of you trying to produce a simple hypothetical and coming up with an awfully confusing one, maybe the original code isn't as confusing.

如果在ruby中有一行结尾,没有什么不符合习惯的,这是完全符合习惯的,人们总是这么做,当它使代码更清晰的时候。在你的例子中,又很难告诉你假的例子——我不认为这是很难的一行如果告诉发生了什么,这是*的奇怪的结构条件下,代码本身的整体结构,很难告诉到底是应该做的。但是你说你不想重构它,好吧。也许这只是你试图提出一个简单的假设然后提出一个非常令人困惑的假设,也许原始代码没有那么令人困惑。

Your other alternative examples do something else, they are not equivalent. For instance:

你的其他例子做了其他的事情,它们是不相等的。例如:

some_variable = defined?(another_variable) ? true : false

This has different semantics than your first example.

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

  • if another_variable exists at all, then some_variable will be set to true. Even if another_variable exists with the value nil or false. So long as another_variable exists, some_variable will be set to true.
  • 如果存在一个other_variable,那么some_variable将被设置为true。即使another_variable存在值为nil或false。只要存在一个other_variable, some_variable将被设置为true。
  • If another_variable does not exist at all some_variable will be set to false.
  • 如果一个other_variable根本不存在,那么some_variable将被设置为false。
  • There is no case where some_variable will be untouched.
  • 在任何情况下,some_variable都不会被修改。

If that's really what you intend to do, then there certainly is a more concise alternative. defined? returns nil if the variable is not defined, otherwise a string explaining the nature of the defined variable. If you want to turn that into strictly boolean true or false, you can use a double boolean negation: some_variable = !! defined?(another_variable). Recall that in ruby anything but false or nil is evaluated as truthy in a boolean context, so !! foo will turn into false if foo was nil or false, and true if foo was anything else.

如果这是你真正想做的,那么肯定有一个更简洁的选择。定义?如果变量未定义,则返回nil,否则将返回解释已定义变量性质的字符串。如果您想将其转换为严格的布尔真或假,您可以使用双布尔否定:some_variable = !定义?(another_variable)。回想一下,在ruby中,除了false或nil之外的任何东西都在布尔上下文中被当作是真实的,所以!如果foo是nil或false, foo就会变成false,如果foo是别的东西,就变成true。

People also just commonly do some_variable = defined?(another_variable) and figure that's good enough to capture "did another_variable exist", since some_variable will still be evaluated the same in a boolean test. Although really, in idiomatic ruby you only occasionally need defined? at all, mostly you are working with variables you already know exist, and you don't need to test to see if they do, and even more seldom do you need to store the results of that test in a variable.

人们通常也会做some_variable = defined?(another_variable)和图,这就足够好了,可以获取“another_variable存在”,因为some_variable在布尔测试中仍然会得到相同的评价。尽管如此,在惯用的ruby中,您偶尔只需要定义?总之,大多数情况下,您使用的是您已经知道的变量,您不需要进行测试来查看它们是否存在,甚至您很少需要将该测试的结果存储在一个变量中。

Your additional examples all have yet different semantics again, none of them are actually equivalent. Hopefully I've given you the tools here to see what they all actually do. You can also try them all out in a little test script, or in the irb REPL.

您的额外示例都有不同的语义,它们实际上都不是等价的。希望我已经给了你们这些工具来看看它们的实际作用。您还可以在一个小测试脚本或irb REPL中尝试所有这些。

I suspect neither of these are what you actually want to do. It depends on the actual semantics you want, which you haven't told us. If your first version you start out with actually does represent the semantics you want, then I think there's no shorter way to do it.

我猜这两个都不是你真正想做的。它取决于你想要的实际语义,你还没有告诉我们。如果你的第一个版本确实代表了你想要的语义,那么我认为没有更短的方法。

You say you are refactoring existing code -- Based on this example you give us, I think the existing code may likely be a mess, with lots of bugs in it, written strangely, and with lack of certainty about what it's even supposed to do, since you aren't the original developer. I'm guessing it doesn't have any tests either. In this situation, I'd start by writing some tests establishing what the code is supposed to do, and then you can try refactoring and make sure it still performs as expected. Without that, and with such messy code, and especially with being newish to ruby, your refactoring is highly likely to change the semantics of the program when you weren't intending to, likely introducing new and even stranger bugs.

你说你是重构现有代码——根据你这个例子给我们,我认为现有的代码可能会一团糟,有很多错误,写奇怪的是,和缺乏确定性甚至应该做什么,因为你不是最初的开发人员。我猜它也没有任何测试。在这种情况下,我将首先编写一些测试来确定代码应该做什么,然后您可以尝试重构并确保它仍然按预期执行。如果没有这些,而且代码也很混乱,尤其是ruby还不成熟,重构很可能会在你不希望的情况下改变程序的语义,可能会引入新的甚至更奇怪的bug。

#2


2  

You don't need that true if <var> part and can use !!instead:

如果部分可以使用!!

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