。尝试VS &&性能

问题描述:

假设我有一个输入值从SQL查询,像这样:。尝试VS &&性能

grok = Foo.select(:foo_attr1, :foo_attr2).first 

foo_attr2是一个可为空场。现在假设我需要对输出做些什么,如果它存在的话。

krug = grok.foo_attr2.try(:bar).try(:baz) 
gnar = grok.foo_attr2 && grok.foo_attr2.bar.baz # Assumes bar will always return output that can be baz'd 

这两个操作哪个更好用,为什么?

+0

页面加载时间似乎已经略有删减推迟到&,可能是因为nilness只需要检查一次而不是两次。另一方面,使用&&会占用更多的空间,这在使用长名称时是一个真正的熊。 – Vardarac 2014-10-30 15:37:06

使用gnar = grok.foo_attr2 && grok.foo_attr2.bar.baz肯定会更快,因为它使用Ruby的逻辑运算符完成。虽然try由Rails引入,并进行额外的if-else条件检查。从代码:

# File activesupport/lib/active_support/core_ext/object/try.rb, line 41 
def try(*a, &b) 
    if a.empty? && block_given? 
    yield self 
    else 
    public_send(*a, &b) if respond_to?(a.first) 
    end 
end 

嗯,这里是一个标杆,以显示正是我想说:

class Object 
    def try(*a, &b) 
    if a.empty? && block_given? 
     yield self 
    else 
     public_send(*a, &b) if respond_to?(a.first) 
    end 
    end 
end 

class Foo 
    attr_reader :a 
    def initialize(a = nil) 
    @a = a  
    end 
end 

require "benchmark" 


bar = Foo.new 
baz = Foo.new(1) 

n = 10000000 
Benchmark.bm(40) do |x| 
    x.report("try"){ n.times { bar.a.try(:class).try(:to_s) } } 
    x.report("&& "){ n.times { baz.a && baz.a.class.to_s } } 
end 

结果是:

  user  system  total  real 
try  10.800000 0.030000 10.830000 (10.829770) 
&&  3.940000 0.010000 3.950000 ( 3.944375)