||之间的差异和内联if语句?

时间:2014-08-29 02:29:00

标签: ruby-on-rails ruby

之间是否存在差异(性能?语义?可读性?)
def test
  x ? x : y
end

def test
  x || y
end?

还想询问有关这种情况的最佳做法。

4 个答案:

答案 0 :(得分:4)

你的第二个例子对Ruby更具惯用性。

def test
  x || y
end

它使用short circuit evaluation在比较中返回第一个“truthy”值。这个和三元运算符之间的性能提升可能是疏忽的。

根据经验,我会说我在Ruby中经常看不到三元运算符。上述x || y表单不起作用的一种情况是您要选择非空字符串。在Ruby中""是真实的,因此"" || "abc"将是true。在这种情况下,三元运算符(或常规if语句)可以很好地工作:

str.empty? ? "abc" : str

参考文献:

答案 1 :(得分:3)

我更喜欢x || y版本,但这取决于xy是什么。我觉得它更具可读性,因为你不必重复x

至于快速而肮脏的基准测试显示没有太多(如果有任何差异)

require 'benchmark'
n=1_000_000
Benchmark.bm do |b|
  b.report("||")  { n.times do ;  x=true; y=2; x || y; end }
  b.report("? :") { n.times do ;  x=true; y=2; x ? x :y ; end }
end

运行1

[~] ruby foo.rb
       user     system      total        real
||  0.080000   0.000000   0.080000 (  0.076901)
? :  0.080000   0.000000   0.080000 (  0.076868)

运行2

[~] ruby foo.rb
       user     system      total        real
||  0.070000   0.000000   0.070000 (  0.076943)
? :  0.080000   0.000000   0.080000 (  0.077277)

运行3

[~] ruby foo.rb
       user     system      total        real
||  0.070000   0.000000   0.070000 (  0.075403)
? :  0.080000   0.000000   0.080000 (  0.076831)


[~] ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]

答案 2 :(得分:1)

可读性

我更喜欢x || y

语义

总结:完全一样。

这是我的测试:

ternary = ->(x, y) { x ? x : y }
ord = ->(x, y) { x || y }
puts "Ternary nil, nil: #{ternary.call(nil, nil)}"
puts "Or'd    nil, nil: #{ord.call(nil, nil)}"
puts "Ternary nil, 1:   #{ternary.call(nil, 1)}"
puts "Or'd    nil, 1:   #{ord.call(nil, 1)}"
puts "Ternary 1,   nil: #{ternary.call(1, nil)}"
puts "Or'd    1,   nil: #{ord.call(1, nil)}"
puts "Ternary 1,   2:   #{ternary.call(1, 2)}"
puts "Or'd    1,   2:   #{ord.call(1, 2)}"

结果是:

Ternary nil, nil: 
Or'd    nil, nil: 
Ternary nil, 1:   1
Or'd    nil, 1:   1
Ternary 1,   nil: 1
Or'd    1,   nil: 1
Ternary 1,   2:   1
Or'd    1,   2:   1

效果

总结:速度差异可以忽略不计,如果重要的话,你可能不应该选择Ruby。

这是我的测试:

require 'benchmark'

n = 10_000_000
Benchmark.bm do |b|
  b.report("T n,n") { n.times do; x=nil; y=nil; x ? x : y; end }
  b.report("O n,n") { n.times do; x=nil; y=nil; x || y; end }
  puts
  b.report("T n,1") { n.times do; x=nil; y=1; x ? x : y; end }
  b.report("O n,1") { n.times do; x=nil; y=1; x || y; end }
  puts
  b.report("T 1,n") { n.times do; x=1; y=nil; x ? x : y; end }
  b.report("O 1,n") { n.times do; x=1; y=nil; x || y; end }
  puts
  b.report("T 1,2") { n.times do; x=1; y=2; x ? x : y; end }
  b.report("O 1,2") { n.times do; x=1; y=2; x || y; end }
end

结果是:

       user     system      total        real
T n,n  0.720000   0.000000   0.720000 (  0.715549)
O n,n  0.780000   0.000000   0.780000 (  0.781091)

T n,1  0.580000   0.000000   0.580000 (  0.579195)
O n,1  0.630000   0.000000   0.630000 (  0.636524)

T 1,n  0.580000   0.000000   0.580000 (  0.572820)
O 1,n  0.600000   0.000000   0.600000 (  0.599424)

T 1,2  0.580000   0.000000   0.580000 (  0.588349)
O 1,2  0.590000   0.000000   0.590000 (  0.587952)

答案 3 :(得分:0)

从语义上讲,没有区别。如果x为假,则检查x的真实性和回退到y。第一个是更具可读性,并且在其使用方面更强大(例如,如果你想在x为真时返回z)。

在性能方面,我运行了1亿次迭代的基准测试。

                       user     system      total        real
if-else                5.480000   0.010000   5.490000 (  5.485275)
or                     5.580000   0.010000   5.590000 (  5.597094)

结果非常接近,几乎没有任何区别。

require 'benchmark'
x = false
y = 1
iterations = 100_000_000

Benchmark.bm(20) do |bm|
  bm.report('if-else') do
    iterations.times { z = x ? x : y }
  end

  bm.report('or') do
    iterations.times { z = x || y }
  end
end