Answers:
证明:
a = 'foo'
a.object_id #=> 2154889340
a << 'bar'
a.object_id #=> 2154889340
a += 'quux'
a.object_id #=> 2154742560
因此,<<
更改原始字符串而不是创建新字符串。这是因为在ruby中,ruby a += b
是语法赋值(a = a + b
其他<op>=
运算符也是如此)。另一方面,<<
它的别名concat()
会改变接收器的位置。
性能证明:
#!/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时问了我同样的问题。我用以下类比向他解释了这一点:
您的一杯水已满,并且需要重新装满一杯。
第一种方法是,拿起新杯子,用自来水将水倒入一半,然后再用第二半满的杯子重新装满水杯。每当您需要重新装满玻璃杯时,都可以这样做。
第二种方法是将半满的玻璃杯装满水,然后直接从水龙头中重新装满水。
在一天结束时,如果您每次需要补充玻璃杯时都选择摘新玻璃杯,那么您将需要清洁更多的玻璃杯。
铲子运算符和加等于运算符也是如此。另外,equal操作员每次需要重新装满玻璃时都会选择一个新的“玻璃杯”,而铲子操作员只需取同样的玻璃杯并重新装满。最终,Plus equal操作员将获得更多“眼镜”收藏。
尽管大多数答案+=
由于创建新副本而较慢,但请记住这一点+=
并且<<
不可互换,这一点很重要!您想在不同的情况下使用它们。
使用<<
还将更改指向的所有变量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"
因为+=
创建了一个新副本,所以它也使指向该副本的所有变量保持不变。
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"
理解这种区别可以在处理循环时省去很多麻烦!
虽然不是您问题的直接答案,但为什么《The Fully Upturned Bin》一直是我最喜欢的Ruby文章之一。它还包含有关垃圾收集的一些字符串信息。