Ruby“返回,除非是”成语

时间:2011-06-15 06:00:53

标签: ruby idioms

我有一个像臭的方法:

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

对于“除非零”的“回复结果”,是否有一个好的红宝石成语?

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

(注意每个调用的args不同,所以我不能简单地迭代它们)

2 个答案:

答案 0 :(得分:20)

您是否关心此处nilfalse之间的区别?如果你只关心每个方法的返回值是否为“falsy”,那么这是一种非常Ruby的方式:

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

如果您不熟悉这个习语,可以这样解释:Ruby,就像大多数语言一样,"short circuits" OR比较,这意味着如果第一个操作数评估为“truey”,它就不会费心去评估第二个操作数(即如果expensive_operation_1返回除nilfalse之外的其他内容,它将永远不会调用expensive_operation_2),因为它已经知道布尔值的结果操作是真的。

Ruby所做的另一个有用的事情是,它不是从布尔运算中返回truefalse,而是返回它评估的最后一个操作数。所以在这种情况下如果expensive_operation_1返回nil,它将调用expensive_operation_2,如果返回一个值(不是假的),整个表达式将只计算为该值

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

答案 1 :(得分:2)

补充Jordan的答案:让我们假设这些函数可以返回一个布尔值(不太可能是搜索函数,但无论如何)并且||不起作用。然后我们可以使用所讨论的抽象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