为什么在Ruby中构buildstring时,铲运算符(<<)优先于plus-equals(+ =)?

我正在通过Ruby Koans工作。

test_the_shovel_operator_modifies_the_original_string中的test_the_shovel_operator_modifies_the_original_string Koan包含以下注释:

在构buildstring时,Ruby程序员倾向于在正等号运算符(+ =)上使用铲子运算符(<<)。 为什么?

我的猜测是涉及速度,但我不明白在引擎盖下的动作会导致铲车运行速度更快。

有人能够解释这个偏好背后的细节吗?

certificate:

 a = 'foo' a.object_id #=> 2154889340 a << 'bar' a.object_id #=> 2154889340 a += 'quux' a.object_id #=> 2154742560 

所以<<改变原来的string而不是创build一个新的string。 原因是在ruby中, a += ba = a + b语法简写(对于其他<op>=运算符也是如此),这是一个赋值。 另一方面, <<concat()的别名,它改变了接收者的位置。

性能certificate:

 #!/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) 

一位正在学习Ruby作为他的第一个编程语言的朋友问我同样的问题,同时在Ruby Koans系列中阅读Ruby中的Strings。 我用下面的比喻向他解释;

你有一杯半满的水,你需要补充杯子。

第一种方法是用一个新的玻璃杯,用水龙头把水填满,然后用这个半满的玻璃杯来填满你的水杯。 每次你需要补充杯子,你都这样做。

第二种方法,你把你的半满玻璃,直接从水龙头充满水。

在一天结束的时候,如果您每次需要重新装满玻璃杯时都select新的玻璃杯,则需要更多的玻璃杯进行清洁。

铲运营商和正加运营商也是如此。 加上相同的操作人员在每次需要重新装满玻璃杯时都会select一个新的“玻璃杯”,而铲车操作员只需将相同的玻璃杯重新装满即可。 在一天结束的时候,更多的'玻璃'收集为加号平等运营商。

这是一个古老的问题,但我只是碰到了这个问题,我对现有的答案并不完全满意。 关于铲子“快于连接+ =”有许多好处,但也有一个语义考虑。

从@noodl接受的答案表明<<修改现有的对象,而+ =创build一个新的对象。 因此,您需要考虑是否希望对string的所有引用都反映新值,或者是否要单独保留现有的引用,并创build一个新的string值以在本地使用。 如果你需要所有的引用来反映更新的值,那么你需要使用<<。 如果你想单独留下其他的引用,那么你需要使用+ =。

一个很常见的情况是只有一个string的引用。 在这种情况下,语义上的差异并不重要,因为它的速度,所以更喜欢“自然”。

因为速度更快/不会创buildstring的副本< – >垃圾收集器不需要运行。

虽然不能直接回答你的问题,但为什么“完全受限制的垃圾箱”一直是我最喜欢的Ruby文章之一。 它也包含一些关于垃圾回收的信息。