81

我刚刚开始学习 Ruby(第一次编程),并且有一个关于变量的基本句法问题,以及各种编写代码的方式。

Chris Pine 的“学习编程”教我编写这样的基本程序......

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 是一种更短的方法。

我应该使用一种格式而不是另一种格式有什么特别的原因吗?

4

5 回答 5

76

每当 TIMTOWTDI(有不止一种方法可以做到这一点)时,您应该寻找利弊。使用“字符串插值”(第二个)而不是“字符串连接”(第一个):

优点:

  • 打字少
  • 自动呼叫to_s
  • 在 Ruby 社区中更惯用
  • 在运行时更快地完成

缺点:

  • 自动调用to_s你(也许你认为你有一个字符串,并且to_s表示不是你想要的,并且隐藏了它不是字符串的事实)
  • 要求您使用"来分隔您的字符串而不是'(也许您有使用的习惯',或者您之前使用它输入了一个字符串,只是后来才需要使用字符串插值)
于 2012-04-09T16:49:55.227 回答
9

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

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

结论

如果字符串已经定义并且确定它们永远不会为零,则使用连接,否则使用插值。使用适当的字符串,这将比易于缩进的字符串带来更好的性能。

于 2014-04-11T11:32:17.913 回答
4

@ user1181898 - 恕我直言,这是因为更容易看到正在发生的事情。就@Phrogz 而言,字符串插值会自动为您调用 to_s。作为初学者,您需要了解“幕后”发生的事情,以便您学习概念,而不是仅仅死记硬背。

把它想象成学习数学。您学习“漫长”的方式是为了理解这些概念,这样一旦您真正知道自己在做什么,就可以走捷径。我从经验 b/c 说我在 Ruby 方面还没有那么先进,但是我犯了足够多的错误来建议人们不要做什么。希望这可以帮助。

于 2012-04-09T17:01:21.853 回答
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

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

于 2016-11-15T02:08:02.690 回答
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

ruby 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
于 2020-02-06T11:34:00.860 回答