eri*_*own 149 ruby string optimization
我正在研究Ruby Koans.
about_strings.rb中的test_the_shovel_operator_modifies_the_original_stringKoan 包含以下注释:
在构建字符串时,Ruby程序员倾向于使用铲运算符(<<)而不是正等运算符(+ =).为什么?
我的猜测是它涉及速度,但我不明白引擎盖下的动作会导致铲子操作员更快.
有人能够解释这个偏好背后的细节吗?
noo*_*odl 253
证明:
a = 'foo'
a.object_id #=> 2154889340
a << 'bar'
a.object_id #=> 2154889340
a += 'quux'
a.object_id #=> 2154742560
Run Code Online (Sandbox Code Playgroud)
因此<<改变原始字符串而不是创建新字符串.其原因在于ruby a += b是一种语法简写a = a + b(对于其他<op>=运算符也是如此),这是一个赋值.另一方面<<,别名concat()可以就地改变接收器.
Nem*_*157 80
绩效证明:
#!/usr/bin/env ruby
require 'benchmark'
Benchmark.bmbm do |x|
x.report('+= :') do
s = ""
10000.times { s += "something " }
end
x.report('<< :') do
s = ""
10000.times { s << "something " }
end
end
# Rehearsal ----------------------------------------
# += : 0.450000 0.010000 0.460000 ( 0.465936)
# << : 0.010000 0.000000 0.010000 ( 0.009451)
# ------------------------------- total: 0.470000sec
#
# user system total real
# += : 0.270000 0.010000 0.280000 ( 0.277945)
# << : 0.000000 0.000000 0.000000 ( 0.003043)
Run Code Online (Sandbox Code Playgroud)
Kib*_*gon 70
一个正在学习Ruby作为他的第一个编程语言的朋友在Ruby Koans系列中通过Ruby中的Strings时问了我同样的问题.我用下面的比喻向他解释了;
你有一杯半满的水,你需要重新装满你的杯子.
第一种方法是采用新玻璃杯,用水龙头将水填充到中途,然后用第二个半满的玻璃杯重新装满水杯.每次需要重新装满玻璃杯时都会这样做.
第二种方式是你拿半满的玻璃杯直接用水龙头加水.
在一天结束时,如果您每次需要重新装满玻璃杯时选择更换新玻璃杯,您可以使用更多眼镜进行清洁.
这同样适用于铲运营商和正等运营商.加上相同的操作员每次需要重新填充玻璃时都会选择一个新的"玻璃",而铲子操作员只需要使用相同的玻璃并重新填充它.在一天结束时,Plus等于运营商的更多"玻璃"收集.
Ton*_*ony 11
这是一个老问题,但我只是碰到了它,我对现有的答案并不完全满意.关于铲子有很多好处,比连接+ =更快,但也有一个语义考虑.
@noodl接受的答案显示<<修改现有对象,而+ =创建一个新对象.因此,您需要考虑是否希望对字符串的所有引用都反映新值,或者您是否希望单独保留现有引用并创建一个新的字符串值以在本地使用.如果您需要所有引用以反映更新的值,那么您需要使用<<.如果你想单独留下其他引用,那么你需要使用+ =.
一个非常常见的情况是对字符串只有一个引用.在这种情况下,语义差异并不重要,因为它的速度,更喜欢<<.
虽然大多数答案的覆盖+=速度较慢,因为它会创建一个新副本,但重要的是要记住这一点+=并且<< 不可互换!您想在不同的情况下使用每个。
使用<<也将改变指向的任何变量b。在这里,我们也a可能不希望发生变异。
2.3.1 :001 > a = "hello"
=> "hello"
2.3.1 :002 > b = a
=> "hello"
2.3.1 :003 > b << " world"
=> "hello world"
2.3.1 :004 > a
=> "hello world"
Run Code Online (Sandbox Code Playgroud)
因为+=创建了一个新副本,所以它还会保留指向它的所有变量不变。
2.3.1 :001 > a = "hello"
=> "hello"
2.3.1 :002 > b = a
=> "hello"
2.3.1 :003 > b += " world"
=> "hello world"
2.3.1 :004 > a
=> "hello"
Run Code Online (Sandbox Code Playgroud)
当您处理循环时,理解这种区别可以为您省去很多麻烦!