Почему оператор buov (<<) предпочитает над плюсом-равными (+ =) при построении строки в Ruby?

Я работаю через Ruby Koans.

test_the_shovel_operator_modifies_the_original_string Koan в about_strings.rb содержит следующий комментарий:

Программисты Ruby, как правило, предпочитают оператора лопаты (<) по сравнению с плюсом equally operator (+ =) при создании строк. Почему?

Я предполагаю, что это скорость, но я не понимаю действия под капотом, что приведет к ускорению работы лопаты.

Кто-нибудь сможет объяснить подробности этого предпочтения?

Ответ 1

Доказательство:

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

Итак, << изменяет исходную строку, а не создает новую. Причина этого в том, что в ruby ​​ a += b есть синтаксическая стенограмма для a = a + b (то же самое относится к другим операторам <op>=), которая является назначением. С другой стороны, << является псевдонимом concat(), который изменяет приемник на месте.

Ответ 2

Доказательство эффективности:

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

Ответ 3

Друг, который изучает Ruby в качестве своего первого языка программирования, задал мне этот же вопрос, проходя через Strings in Ruby в серии Ruby Koans. Я объяснил это ему, используя следующую аналогию:

У вас есть стакан воды, который наполовину заполнен, и вам нужно пополнить стакан.

Сначала вы сделаете это, взяв новый стакан, наполнив его наполовину водой из крана, а затем используя это второе полуфабрикат, чтобы пополнить стаканчик. Вы делаете это каждый раз, когда вам нужно пополнить свой стакан.

Второй способ: взять половину полного стекла и просто пополнить его водой прямо из крана.

В конце дня у вас будет больше очков для очистки, если вы решите выбрать новый стакан каждый раз, когда вам нужно пополнить свой стакан.

То же самое относится к оператору лопаты и плюсовому оператору. Плюс равный оператор выбирает новое "стекло" каждый раз, когда ему нужно пополнить его стекло, в то время как оператор лопаты просто берет тот же стакан и заправляет его. В конце дня большая коллекция "стекла" для оператора "Плюс".

Ответ 4

Это старый вопрос, но я просто столкнулся с ним, и я не полностью удовлетворен существующими ответами. Есть много хороших точек относительно лопаты < быстрее, чем конкатенация + =, но есть также семантическое соображение.

Принятый ответ от @noodl показывает, что < изменяет существующий объект на месте, тогда как + = создает новый объект. Поэтому вам нужно учитывать, хотите ли вы, чтобы все ссылки на строку отражали новое значение, или вы хотите оставить только существующие ссылки и создать новое строковое значение для локального использования. Если вам нужны все ссылки для отражения обновленного значения, тогда вам нужно использовать < <. Если вы хотите оставить только другие ссылки, вам нужно использовать + =.

Очень распространенный случай: существует только одна ссылка на строку. В этом случае семантическая разница не имеет значения, и естественно предпочесть < из-за его скорости.

Ответ 5

Поскольку он быстрее/не создает копию сборника мусора строки ↔ , не нужно запускать.