2011-06-15 39 views
15

我有一个臭方法,如:红宝石“回报,除非无”成语

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)方法?

(请注意,ARG游戏为每个调用不同的,所以我不能只是简单地在它们之间迭代)

+0

可以记录为'false',或者绝对是真实记录还是零? – 2011-06-15 06:07:28

+0

“或者我应该写一个'return_unless_nil(&blk)'方法?”哪个会从调用它的方法返回?我不认为这是可能的。 – 2011-06-15 06:10:35

+0

我有约10分钟的时间在学习红宝石,但我很好奇你会怎么写一个方法来为调用者返回一个值?至于一个潜在的答案,我觉得这是一个真正的答案,因为我的红宝石曝光非常有限......你可以在红宝石中使用类似的东西吗? 'return(record = expensive_op(foo))除非record.nil?'不知道这对你是否有点臭? – 2011-06-15 06:13:09

回答

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 

如果你不熟悉这个成语,它可以解释正是如此:红宝石,如同大多数语言一样,"short circuits"或比较,意思是如果第一个操作数的计算结果为“truey”,则不会费心去评估第二个操作数(即如果expensive_operation_1返回nilfalse以外的东西,它将不会呼叫expensive_operation_2) ,因为它已经知道布尔运算的结果是真的。

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

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

+0

要扩展Jordan的相当简洁的答案:布尔运算符短路(如果不需要右侧,则只计算左侧)并返回满足运算符的值。 – Chuck 2011-06-15 06:13:12

+0

谢谢查克。当你评论时,我正忙于扩展我的答案。 :) – 2011-06-15 06:14:17

+0

需要注意的是,“你关心零与假之间的区别”的确很重要。如果这些函数中的任何一个返回一个布尔值,这段代码将不会执行。不幸的是,OP已经走了。 – tokland 2011-06-15 11:04:09

2

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

Object#or_if是一个值得记住的有趣成语。谢谢! – pithyless 2011-06-15 18:00:39