Ruby“除非nil否则返回”成语

发布于 2024-11-15 09:17:20 字数 524 浏览 2 评论 0原文

我有一个像这样的臭方法:

def search_record(*args)    
  record = expensive_operation_1(foo)
  return record unless record.nil?

  record = expensive_operation_2(foo, bar)
  return record unless record.nil?

  record = expensive_operation_3(baz)
  return record unless record.nil?

  record = expensive_operation_4(foo, baz)
  return record unless record.nil?
end

是否有一个好的红宝石习惯用法“返回调用结果,除非nil”?

或者我应该只编写一个 return_unless_nil(&blk) 方法?

(请注意,每次调用的参数都不同,因此我不能简单地迭代它们)

I've got a smelly method like:

def search_record(*args)    
  record = expensive_operation_1(foo)
  return record unless record.nil?

  record = expensive_operation_2(foo, bar)
  return record unless record.nil?

  record = expensive_operation_3(baz)
  return record unless record.nil?

  record = expensive_operation_4(foo, baz)
  return record unless record.nil?
end

Is there a good ruby idiom for "return result of call unless nil"?

Or should I just write a return_unless_nil(&blk) method?

(Note that args are different for each call, so I can't simply just iterate over them)

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

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

发布评论

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

评论(2

风筝在阴天搁浅。 2024-11-22 09:17:20

你关心这里的nilfalse的区别吗?如果您只关心每个方法的返回值是否为“falsy”,那么这是一种相当 Rubyish 的做法:

def search_record(*args)    
  expensive_operation_1(foo)      ||
  expensive_operation_2(foo, bar) ||
  expensive_operation_3(baz)      ||
  expensive_operation_4(foo, baz)
end

如果您不熟悉这个习惯用法,可以这样解释:Ruby,像大多数语言一样,"短路" OR 比较,这意味着如果第一个操作数的计算结果为"truey" 它不会费心计算第二个操作数(即,如果 exppressive_operation_1 返回 nilfalse 以外的内容,它不会曾经调用expense_operation_2),因为它已经知道布尔运算的结果是true。

Ruby 所做的另一件有用的事情是,它不从布尔运算返回 true 或 false,而是仅返回它计算的最后一个操作数。因此,在这种情况下,如果 exppressive_operation_1 返回 nil,它将调用 exppressive_operation_2,并且如果返回一个值(不是假值),整个表达式将计算为该值。

最后,我们可以链接这些布尔值,这样,实际上,它将返回第一个不为假的操作数的结果,并且永远不会评估后续操作数。如果所有操作数的计算结果为假,它将返回最终操作数(我们知道它是假的,在您的情况下,可能nil)。

Do you care about the difference between nil and false here? If you only care whether the return value of each method is "falsy," then this is a pretty Rubyish way of doing it:

def search_record(*args)    
  expensive_operation_1(foo)      ||
  expensive_operation_2(foo, bar) ||
  expensive_operation_3(baz)      ||
  expensive_operation_4(foo, baz)
end

If you're unfamiliar with this idiom, it can be explained thusly: Ruby, like most languages, "short circuits" OR comparisons, meaning that if the first operand evaluates to "truey" it won't bother to evaluate the second operand (i.e. if expensive_operation_1 returns something other than nil or false, it won't ever call expensive_operation_2), because it already knows that the result of the boolean operation is true.

Another useful thing that Ruby does is, instead of returning true or false from boolean operations it just returns the last operand it evaluates. So in this case if expensive_operation_1 returns nil, it will then call expensive_operation_2, and if that returns a value (that isn't falsy), the whole expression will just evaluate to that value.

Finally, we can chain these booleans so, in effect, it will return the result of the first operand that isn't falsy and never evaluate the subsequent operands. If all of the operands evaluate to falsy, it will return the final operand (which we know is falsy and, in your case, probably nil).

花想c 2024-11-22 09:17:20

补充乔丹的答案:让我们想象这些函数可以返回一个布尔值(对于搜索函数来说不太可能,但无论如何)并且 || 不起作用。然后,我们可以使用此处讨论的抽象

expensive_operation_1(foo).or_if(:nil?) do
  expensive_operation_2(foo).or_if(:nil?) do
    expensive_operation_3(foo).or_if(:nil?) do
      expensive_operation_4(foo)
    end
  end
end

Complementing Jordan's answer: let's imagine these functions could return a boolean (unlikely for a search function, but anyway) and || does not work. We could then use the abstraction discussed here:

expensive_operation_1(foo).or_if(:nil?) do
  expensive_operation_2(foo).or_if(:nil?) do
    expensive_operation_3(foo).or_if(:nil?) do
      expensive_operation_4(foo)
    end
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文