Конкатенация строк и интерполяция в Ruby

Я только начинаю изучать Ruby (первое программирование) и иметь базовый синтаксический вопрос относительно переменных и различные способы написания кода.

Крис Пайн "Учись программировать" научил меня писать базовую программу, подобную этой...

num_cars_again= 2
puts 'I own ' + num_cars_again.to_s + ' cars.'

Это прекрасно, но затем я наткнулся на учебник по ruby.learncodethehardway.com и научился писать ту же самую точную программу, как это...

num_cars= 2
puts "I own #{num_cars} cars."

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

Есть ли какая-то особая причина, почему я должен использовать один формат над другим?

Ответ 1

Всякий раз, когда TIMTOWTDI (есть более чем один способ сделать это), вы должны искать плюсы и минусы. Использование "строковой интерполяции" (вторая) вместо "конкатенации строк" ​​(первая):

Плюсы:

  • Не печатается
  • Автоматически вызывает to_s для вас
  • Больше идиоматических в сообществе Ruby.
  • Быстрее выполнять во время выполнения

Минусы:

  • Автоматически вызывает to_s для вас (возможно, вы считали, что у вас есть строка, а представление to_s не то, что вы хотели, и скрывает тот факт, что это не строка)
  • Требуется использовать ", чтобы разграничить вашу строку вместо ' (возможно, у вас есть привычка использовать ', или вы ранее набрали строку, используя это, и только позже нужно использовать интерполяцию строк)

Ответ 2

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

require 'benchmark'

iterations = 1_00_000
firstname = 'soundarapandian'
middlename = 'rathinasamy'
lastname = 'arumugam'

puts 'With dynamic new strings'
puts '===================================================='
5.times do
  Benchmark.bm(10) do |benchmark|
    benchmark.report('concatination') do
      iterations.times do
        'Mr. ' + firstname + middlename + lastname + ' aka soundar'
      end
    end

    benchmark.report('interpolaton') do
      iterations.times do
        "Mr. #{firstname} #{middlename} #{lastname} aka soundar"
      end
    end
  end
  puts '--------------------------------------------------'
end

puts 'With predefined strings'
puts '===================================================='
5.times do
  Benchmark.bm(10) do |benchmark|
    benchmark.report('concatination') do
      iterations.times do
        firstname + middlename + lastname
      end
    end

    benchmark.report('interpolaton') do
      iterations.times do
        "#{firstname} #{middlename} #{lastname}"
      end
    end
  end
  puts '--------------------------------------------------'
end

И ниже приведен результат теста

Without predefined strings
====================================================
                 user     system      total        real
concatination  0.170000   0.000000   0.170000 (  0.165821)
interpolaton  0.130000   0.010000   0.140000 (  0.133665)
--------------------------------------------------
                 user     system      total        real
concatination  0.180000   0.000000   0.180000 (  0.180410)
interpolaton  0.120000   0.000000   0.120000 (  0.125051)
--------------------------------------------------
                 user     system      total        real
concatination  0.140000   0.000000   0.140000 (  0.134256)
interpolaton  0.110000   0.000000   0.110000 (  0.111427)
--------------------------------------------------
                 user     system      total        real
concatination  0.130000   0.000000   0.130000 (  0.132047)
interpolaton  0.120000   0.000000   0.120000 (  0.120443)
--------------------------------------------------
                 user     system      total        real
concatination  0.170000   0.000000   0.170000 (  0.170394)
interpolaton  0.150000   0.000000   0.150000 (  0.149601)
--------------------------------------------------
With predefined strings
====================================================
                 user     system      total        real
concatination  0.070000   0.000000   0.070000 (  0.067735)
interpolaton  0.100000   0.000000   0.100000 (  0.099335)
--------------------------------------------------
                 user     system      total        real
concatination  0.060000   0.000000   0.060000 (  0.061955)
interpolaton  0.130000   0.000000   0.130000 (  0.127011)
--------------------------------------------------
                 user     system      total        real
concatination  0.090000   0.000000   0.090000 (  0.092136)
interpolaton  0.110000   0.000000   0.110000 (  0.110224)
--------------------------------------------------
                 user     system      total        real
concatination  0.080000   0.000000   0.080000 (  0.077587)
interpolaton  0.110000   0.000000   0.110000 (  0.112975)
--------------------------------------------------
                 user     system      total        real
concatination  0.090000   0.000000   0.090000 (  0.088154)
interpolaton  0.140000   0.000000   0.140000 (  0.135349)
--------------------------------------------------

Заключение

Если строки уже определены и уверены, что они никогда не будут использоваться, используйте concatination else, используя интерполяцию. Используйте подходящую, которая приведет к лучшей производительности, чем та, которая проста в отступлении.

Ответ 3

@user1181898 - ИМХО, это потому, что легче увидеть, что происходит. Точка @Phrogz, строка-интерполяция автоматически вызывает to_s для вас. Как новичок, вам нужно посмотреть, что происходит "под капотом", чтобы вы научились концепции, а не просто учились на rote.

Подумайте об этом, как об изучении математики. Вы изучаете "длинный" способ, чтобы понять концепции, чтобы вы могли использовать ярлыки, когда вы действительно знаете, что делаете. Я говорю по опыту b/c. Я еще не продвинулся в Ruby, но я допустил достаточно ошибок, чтобы советовать людям, что не делать. Надеюсь, это поможет.

Ответ 4

Если вы используете строку в качестве буфера, я обнаружил, что использование конкатенации (String#concat) выполняется быстрее.

require 'benchmark/ips'

puts "Ruby #{RUBY_VERSION} at #{Time.now}"
puts

firstname = 'soundarapandian'
middlename = 'rathinasamy'
lastname = 'arumugam'

Benchmark.ips do |x|
    x.report("String\#<<") do |i|
        buffer = String.new

        while (i -= 1) > 0
            buffer << 'Mr. ' << firstname << middlename << lastname << ' aka soundar'
        end
    end

    x.report("String interpolate") do |i|
        buffer = String.new

        while (i -= 1) > 0
            buffer << "Mr. #{firstname} #{middlename} #{lastname} aka soundar"
        end
    end

    x.compare!
end

Результаты:

Ruby 2.3.1 at 2016-11-15 15:03:57 +1300

Warming up --------------------------------------
           String#<<   230.615k i/100ms
  String interpolate   234.274k i/100ms
Calculating -------------------------------------
           String#<<      2.345M (± 7.2%) i/s -     11.761M in   5.041164s
  String interpolate      1.242M (± 5.4%) i/s -      6.325M in   5.108324s

Comparison:
           String#<<:  2344530.4 i/s
  String interpolate:  1241784.9 i/s - 1.89x  slower

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

Ответ 5

Только для записи можно использовать как двойные, так и одинарные кавычки с интерполяцией. Оба являются обычным кодом. Итак:

num_cars= 2
puts "I own #{num_cars} cars."
puts 'I own #{num_cars} cars.'