我正在寻找一种在Ruby中连接字符串的更优雅的方式。

我有如下一行:

source = "#{ROOT_DIR}/" << project << "/App.config"

有更好的方法吗?

那么<<和+之间有什么区别呢?


当前回答

下面是受这个要点启发的另一个基准测试。它比较动态和预定义字符串的连接(+)、追加(<<)和插值(#{})。

require 'benchmark'

# we will need the CAPTION and FORMAT constants:
include Benchmark

count = 100_000


puts "Dynamic strings"

Benchmark.benchmark(CAPTION, 7, FORMAT) do |bm|
  bm.report("concat") { count.times { 11.to_s +  '/' +  12.to_s } }
  bm.report("append") { count.times { 11.to_s << '/' << 12.to_s } }
  bm.report("interp") { count.times { "#{11}/#{12}" } }
end


puts "\nPredefined strings"

s11 = "11"
s12 = "12"
Benchmark.benchmark(CAPTION, 7, FORMAT) do |bm|
  bm.report("concat") { count.times { s11 +  '/' +  s12 } }
  bm.report("append") { count.times { s11 << '/' << s12 } }
  bm.report("interp") { count.times { "#{s11}/#{s12}"   } }
end

输出:

Dynamic strings
              user     system      total        real
concat    0.050000   0.000000   0.050000 (  0.047770)
append    0.040000   0.000000   0.040000 (  0.042724)
interp    0.050000   0.000000   0.050000 (  0.051736)

Predefined strings
              user     system      total        real
concat    0.030000   0.000000   0.030000 (  0.024888)
append    0.020000   0.000000   0.020000 (  0.023373)
interp    3.160000   0.160000   3.320000 (  3.311253)

结论:MRI内插重。

其他回答

对于你的特殊情况,你也可以使用array# join构造文件路径类型的字符串:

string = [ROOT_DIR, project, 'App.config'].join('/')]

这有一个令人愉快的副作用,自动将不同类型转换为字符串:

['foo', :bar, 1].join('/')
=>"foo/bar/1"

你说的是串联?那么#concat方法呢?

a = 'foo'
a.object_id #=> some number
a.concat 'bar' #=> foobar
a.object_id #=> same as before -- string a remains the same object

公平地说,concat别名为<<。

这里有更多的方法:

"String1" + "String2"

"#{String1} #{String2}"

String1<<String2

等等……

你可以通过以下几种方式做到这一点:

正如你用<<所示,但这不是通常的方式 用字符串插值 source = "#{ROOT_DIR}/#{项目}/App.config" 与+ source = "#{ROOT_DIR}/" + project + "/App.config"

据我所见,第二种方法在内存/速度方面似乎更有效(虽然没有测量过)。当ROOT_DIR为nil时,这三个方法都会抛出一个未初始化的常量错误。

在处理路径名时,您可能希望使用File。连接以避免混淆路径名分隔符。

说到底,这是一个品味问题。

情况很重要,例如:

# this will not work
output = ''

Users.all.each do |user|
  output + "#{user.email}\n"
end
# the output will be ''
puts output

# this will do the job
output = ''

Users.all.each do |user|
  output << "#{user.email}\n"
end
# will get the desired output
puts output

在第一个示例中,与+操作符连接将不会更新输出对象,然而,在第二个示例中,<<操作符将在每次迭代中更新输出对象。因此,对于上述类型的情况,<<更好。