Почему оператор 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
Поскольку он быстрее/не создает копию сборника мусора строки ↔ , не нужно запускать.
Ответ 6
Не являясь прямым ответом на ваш вопрос, почему "Fully Upturned Bin" всегда был одной из моих любимых статей в Ruby. Он также содержит некоторую информацию о строках в отношении сбора мусора.