如何避免短路评估

发布于 2024-07-11 23:36:19 字数 288 浏览 8 评论 0原文

我正在使用 Ruby on Rails 并希望验证两种不同的模型:

if (model1.valid? && model2.valid?)
...
end

但是,“&&” 运算符使用短路评估(即,仅当“model1.valid?”为真时才评估“model2.valid?”),这会阻止在 model1 无效时执行 model2.valids。

有没有相当于“&&”的 哪个不会使用短路评估? 我需要评估这两个表达式。

I'm working with Ruby on Rails and would like to validate two different models :

if (model1.valid? && model2.valid?)
...
end

However, "&&" operator uses short-circuit evaluation (i.e. it evaluates "model2.valid?" only if "model1.valid?" is true), which prevents model2.valids to be executed if model1 is not valid.

Is there an equivalent of "&&" which would not use short-circuit evaluation? I need the two expressions to be evaluated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

回首观望 2024-07-18 23:36:20

试试这个:

[model1, model2].map(&:valid?).all?

如果两者都有效,它将返回 true,并在两个实例上创建错误。

Try this:

[model1, model2].map(&:valid?).all?

It'll return true if both are valid, and create the errors on both instances.

东风软 2024-07-18 23:36:20

& 工作得很好。

irb(main):007:0> def a
irb(main):008:1> puts "a"
irb(main):009:1> false
irb(main):010:1> end
=> nil

irb(main):011:0> def b
irb(main):012:1> puts "b"
irb(main):013:1> true
irb(main):014:1> end
=> nil

irb(main):015:0> a && b
a
=> false

irb(main):016:0> a & b
a
b
=> false

irb(main):017:0> a and b
a
=> false

& works just fine.

irb(main):007:0> def a
irb(main):008:1> puts "a"
irb(main):009:1> false
irb(main):010:1> end
=> nil

irb(main):011:0> def b
irb(main):012:1> puts "b"
irb(main):013:1> true
irb(main):014:1> end
=> nil

irb(main):015:0> a && b
a
=> false

irb(main):016:0> a & b
a
b
=> false

irb(main):017:0> a and b
a
=> false
娜些时光,永不杰束 2024-07-18 23:36:20

怎么样:

if [model1.valid?,model2.valid?].all?
  ...
end

对我有用。

How about:

if [model1.valid?,model2.valid?].all?
  ...
end

Works for me.

不再见 2024-07-18 23:36:20

分别评估它们并将结果存储在变量中。 然后使用简单的 && 在这些布尔值之间:)

Evaluate them separately and store the result in a variable. Then use a simple && between those booleans :)

绝影如岚 2024-07-18 23:36:20

使代码片段对未来开发人员更易于维护的关键概念之一是其表现力。

让我们考虑以下示例:

([model1, model2].map(&:valid?)).all?

或者

[model1.valid?,model2.valid?].all?

他们都做得很好,但是当未来的开发人员遇到其中任何一个而没有看到任何解释性注释、您意图的文档,或者没有直接联系您时,该开发人员将在不知道的情况下修改它们目的是为了避免短路评估。

如果没有测试,情况会变得更糟。

这就是为什么我建议引入一个小的包装方法,它可以让所有事情立即变得清晰。

def without_short_circuit_evaluation(*conditions)
  conditions.all?
end

然后在你的代码库的某个地方。

if without_short_circuit_evaluation(model1.valid?, model2.valid?)
  # do something
end

One of the key concepts which allow making a code snippet more maintainable for a future developer is its expressiveness.

Let's consider the following examples:

([model1, model2].map(&:valid?)).all?

or

[model1.valid?,model2.valid?].all?

Both of them do their job well, but when a future developer will encounter any of them without seeing any explanatory comments, docs of your intent, or without reaching you directly, this developer will modify them having no idea that the purpose was to avoid the short-circuit evaluation.

Things become even worse when you have no tests.

This is why I suggest introducing a small wrapper method which will make all things clear immediately.

def without_short_circuit_evaluation(*conditions)
  conditions.all?
end

And later somewhere in your codebase.

if without_short_circuit_evaluation(model1.valid?, model2.valid?)
  # do something
end
半城柳色半声笛 2024-07-18 23:36:20

我遇到了类似的问题,我需要检查两个字符串是否不为空。 短路阻止了我检查两个字符串,但我发现在 ruby​​ 中我们可以使用 if not 或除非

return nil if not string1.blank? && string2.blank?

return nil unless string1.present? && string2.present?

I had a similar issue where I needed to check if two string weren't blank. Short circuit was preventing me to check both strings but I found out that in ruby we can use if not or unless

return nil if not string1.blank? && string2.blank?

or

return nil unless string1.present? && string2.present?
羅雙樹 2024-07-18 23:36:20

您可以将一个块传递给 all?,而不是使用 map 创建额外的数组。

[model_instance_1, model_instance_2].all? {|i| i.valid? }

Instead of creating an extra array with map, you can pass a block to all?.

[model_instance_1, model_instance_2].all? {|i| i.valid? }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文