Ruby中的字符串连接与插值

时间:2012-04-09 16:46:39

标签: ruby string-concatenation string-interpolation

我刚开始学习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是一种更短的方法。

为什么我应该使用一种格式而不是另一种格式?

5 个答案:

答案 0 :(得分:70)

每当TIMTOWTDI(有多种方法)时,你应该寻找利弊。使用“字符串插值”(第二个)而不是“字符串连接”(第一个):

<强>优点:

  • 少输入
  • 自动为您调用to_s
  • Ruby社区中的更多惯用语
  • 在运行期间更快完成

<强>缺点:

  • 自动为您调用to_s(也许您认为自己有一个字符串,并且to_s表示不是您想要的,并且隐藏了它不是字符串的事实)
  • 要求您使用"来分隔字符串而非'(或许您习惯使用',或者之前使用该字符串键入字符串,并且仅在以后需要使用字符串插值)

答案 1 :(得分:8)

插值和连接都有自己的优点和缺点。下面我给出了一个基准,它清楚地说明了在何处使用连接以及在何处使用插值。

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)
--------------------------------------------------

<强>结论

如果字符串已经定义并且确定它们永远不会是nil使用concatination,则使用interpolation。使用适当的字符串,这将导致比容易缩进的字符串更好的性能。

答案 2 :(得分:4)

@ user1181898 - 恕我直言,这是因为它更容易看到发生了什么。对于@ Phrogz的观点,字符串插值会自动为您调用to_s。作为一个初学者,你需要看到“引擎盖下”发生了什么,这样你就可以学习这个概念而不仅仅是死记硬背。

把它想象成学习数学。为了理解这些概念,你学习了“长”的方法,这样你就可以在实际知道自己在做什么之后走捷径。我从经验中说起b / c我还没有那么先进的Ruby,但我犯了很多错误,建议人们不要做什么。希望这会有所帮助。

答案 3 :(得分:2)

如果您使用字符串作为缓冲区,我发现使用连接(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

猜测一下,我会说插值会产生一个临时字符串,这就是它变慢的原因。

答案 4 :(得分:0)

这里是一个完整的基准测试,它也比较了Kernel#formatString#+,因为它是我所知道的在ruby中构造动态字符串的所有方法

require 'benchmark/ips'

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

FORMAT_STR = 'Mr. %<firstname>s %<middlename>s %<lastname>s aka soundar'
Benchmark.ips do |x|
  x.report("String\#<<") do |i|
    str = String.new
    str << 'Mr. ' << firstname << ' ' << middlename << ' ' << lastname << ' aka soundar'
  end

  x.report "String\#+" do
    'Mr. ' + firstname + ' ' + middlename + ' ' + lastname + ' aka soundar'
  end

  x.report "format" do
    format(FORMAT_STR, firstname: firstname, middlename: middlename, lastname: lastname)
  end

  x.report("String interpolate") do |i|
    "Mr. #{firstname} #{middlename} #{lastname} aka soundar"
  end

  x.compare!
end

红宝石2.6.5的结果

Warming up --------------------------------------
           String#<<
    94.597k i/100ms
            String#+    75.512k i/100ms
              format    73.269k i/100ms
  String interpolate   164.005k i/100ms
Calculating -------------------------------------
           String#<<     91.385B (±16.9%) i/s -    315.981B
            String#+    905.389k (± 4.2%) i/s -      4.531M in   5.013725s
              format    865.746k (± 4.5%) i/s -      4.323M in   5.004103s
  String interpolate    161.694B (±11.3%) i/s -    503.542B

Comparison:
  String interpolate: 161693621120.0 i/s
           String#<<: 91385051886.2 i/s - 1.77x  slower
            String#+:   905388.7 i/s - 178590.27x  slower
              format:   865745.8 i/s - 186768.00x  slower