我正在尝试缩短此代码:
if a.nil?
a = "foo"
else
a << "foo"
end
a
是nil
或字符串。
我已尝试过a ||= "foo"
和a += "foo"
,但如果a
为nil
,则无效。
答案 0 :(得分:8)
nil.to_s
等于''
所以你可以写
a = a.to_s + 'foo'
或另类
a = "#{a}foo"
答案 1 :(得分:5)
这可能与您的情况无关,但a +=
和a <<
之间存在差异。
+=
为a
分配一个新字符串,保留旧字符串不变:
a = 'abc'
b = a
a += 'foo'
a #=> "abcfoo" # <- a refers to the new string object
b #=> "foo" # <- b still refers to the original string
这是因为String#+
会返回 new 字符串。 a += 'foo'
相当于a = a + 'foo'
。
String#<<
修改现有字符串,它不会创建新字符串:
a = 'abc'
b = a
a << 'foo'
a #=> "abcfoo"
b #=> "abcfoo" # <- both changed, because a and b refer to the same object
因此,为了缩短代码而不改变其行为,您可以使用:
(a ||= '') << 'foo'
如果a ||= ''
为a
, a
会为nil
分配一个空字符串。然后<< 'foo'
将'foo'
追加到a
。
答案 2 :(得分:0)
写如下:
a = a.nil? ? (a.to_s + 'foo') : 'foo'
答案 3 :(得分:0)
如果您想组合2个字符串(其中任意一个可以为nil
),则可以执行以下操作:
a.nil? ? a = (b || '') : a << (b || '')
即使a
,b
或两者均为nil
,此方法也有效。
即使语法有些丑陋,这也比替代方法快得多。
基准:
require 'benchmark'
n = 50_000_000
Benchmark.bm do |x|
x.report("compact.reduce(:+)") { n.times { a = nil; b = 'foo'; a = [a, b].compact.reduce(:+) } }
x.report("string interpolation") { n.times { a = nil; b = 'foo'; a = "#{a}#{b}" } }
x.report("to_s") { n.times { a = nil; b = 'foo'; a = a.to_s + b.to_s } }
x.report("(x || '') +") { n.times { a = nil; b = 'foo'; a = (a || '') + b } }
x.report("(x || '') <<") { n.times { a = nil; b = 'foo'; a = (a || '') << b } } # will throw an exception if used with `frozen_string_literal: true`
x.report("ternary") { n.times { a = nil; b = 'foo'; a.nil? ? a = (b || '') : a << (b || '') } }
end
结果:
user system total real
compact.reduce(:+) 6.677367 0.000000 6.677367 ( 6.677337)
string interpolation 7.983451 0.000000 7.983451 ( 7.983440)
to_s 7.067699 0.000000 7.067699 ( 7.067702)
(x || '') + 5.130624 0.000000 5.130624 ( 5.130585)
(x || '') << 4.809965 0.000000 4.809965 ( 4.809978)
ternary 3.300871 0.000000 3.300871 ( 3.300838)