Почему оператор лопатой (<<) предпочтительнее, чем плюс-равно (+ =) при построении строки в Ruby? - PullRequest
147 голосов
/ 13 января 2011

Я работаю через Руби Коанс.

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

Программисты Ruby предпочитают оператор лопатой (<<) перед плюсомоператор равенства (+ =) при построении строк.Почему? </p>

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

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

Ответы [ 7 ]

249 голосов
/ 13 января 2011

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

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(), который изменяет приемник на месте.

80 голосов
/ 13 января 2011

Доказательство производительности:

#!/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)
70 голосов
/ 21 ноября 2012

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

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

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

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

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

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

11 голосов
/ 22 ноября 2014

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

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

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

10 голосов
/ 13 января 2011

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

3 голосов
/ 02 ноября 2018

Хотя большинство ответов охватывают += медленнее, потому что создает новую копию, важно помнить, что += и << не являются взаимозаменяемыми!Вы хотите использовать каждый из них в разных случаях.

Использование << также изменит любые переменные, на которые указывает 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"

Понимание этого различия поможет вам избежать головной боли при работе с петлями!

2 голосов
/ 14 января 2011

Хотя это и не прямой ответ на ваш вопрос, почему Полностью перевернутая корзина всегда была одной из моих любимых статей на Ruby. Он также содержит некоторую информацию о строках в отношении сборки мусора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...