之间是否存在差异(性能?语义?可读性?)
def test
x ? x : y
end
和
def test
x || y
end?
还想询问有关这种情况的最佳做法。
答案 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
版本,但这取决于x
和y
是什么。我觉得它更具可读性,因为你不必重复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