我正在寻找一种更优雅的方法来在Ruby中连接字符串。
我有以下代码行:
source = "#{ROOT_DIR}/" << project << "/App.config"
有没有更好的方法来做这件事?
此外,<<和+之间有什么区别?
我正在寻找一种更优雅的方法来在Ruby中连接字符串。
我有以下代码行:
source = "#{ROOT_DIR}/" << project << "/App.config"
有没有更好的方法来做这件事?
此外,<<和+之间有什么区别?
<<
,但这不是通常的方式。使用字符串插值
source = "#{ROOT_DIR}/#{project}/App.config"
使用+
运算符
source = "#{ROOT_DIR}/" + project + "/App.config"
根据我的观察(虽然没有测量),第二种方法似乎在内存/速度方面更有效率。无论哪种方法,当ROOT_DIR为nil时都会抛出未初始化常量错误。
处理路径名时,您可能希望使用File.join
来避免弄乱路径名分隔符。
最终,这是一个品味问题。
+
运算符是正常的连接选择,可能是连接字符串最快的方式。
+
和 <<
之间的区别在于,<<
改变其左侧对象,而 +
不会。
irb(main):001:0> s = 'a'
=> "a"
irb(main):002:0> s + 'b'
=> "ab"
irb(main):003:0> s
=> "a"
irb(main):004:0> s << 'b'
=> "ab"
irb(main):005:0> s
=> "ab"
+
和 <<
的效果都差不多。如果你处理很多字符串或者非常大的字符串,那么可能会注意到它们之间的差异。我对它们表现得如此相似感到惊讶。 - Matt Burke5.times do ... end
块中),则可以获得更准确的结果。我的测试表明,在所有Ruby解释器中,插值是最快的方法。我本来以为<<
会是最快的,但这就是我们进行基准测试的原因。 - womble如果你只是要将路径连接起来,你可以使用Ruby自带的File.join方法。
source = File.join(ROOT_DIR, project, 'App.config')
来自http://greyblake.com/blog/2012/09/02/ruby-perfomance-tricks/
使用<<
,也称为concat
,比使用+=
更高效,因为后者会创建一个临时对象,并用新对象覆盖第一个对象。
require 'benchmark'
N = 1000
BASIC_LENGTH = 10
5.times do |factor|
length = BASIC_LENGTH * (10 ** factor)
puts "_" * 60 + "\nLENGTH: #{length}"
Benchmark.bm(10, '+= VS <<') do |x|
concat_report = x.report("+=") do
str1 = ""
str2 = "s" * length
N.times { str1 += str2 }
end
modify_report = x.report("<<") do
str1 = "s"
str2 = "s" * length
N.times { str1 << str2 }
end
[concat_report / modify_report]
end
end
输出:
____________________________________________________________
LENGTH: 10
user system total real
+= 0.000000 0.000000 0.000000 ( 0.004671)
<< 0.000000 0.000000 0.000000 ( 0.000176)
+= VS << NaN NaN NaN ( 26.508796)
____________________________________________________________
LENGTH: 100
user system total real
+= 0.020000 0.000000 0.020000 ( 0.022995)
<< 0.000000 0.000000 0.000000 ( 0.000226)
+= VS << Inf NaN NaN (101.845829)
____________________________________________________________
LENGTH: 1000
user system total real
+= 0.270000 0.120000 0.390000 ( 0.390888)
<< 0.000000 0.000000 0.000000 ( 0.001730)
+= VS << Inf Inf NaN (225.920077)
____________________________________________________________
LENGTH: 10000
user system total real
+= 3.660000 1.570000 5.230000 ( 5.233861)
<< 0.000000 0.010000 0.010000 ( 0.015099)
+= VS << Inf 157.000000 NaN (346.629692)
____________________________________________________________
LENGTH: 100000
user system total real
+= 31.270000 16.990000 48.260000 ( 48.328511)
<< 0.050000 0.050000 0.100000 ( 0.105993)
+= VS << 625.400000 339.800000 NaN (455.961373)
既然这是一个路径,我可能会使用数组和连接:
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)
我更喜欢使用Pathname:
require 'pathname' # pathname is in stdlib
Pathname(ROOT_DIR) + project + 'App.config'
<<
和+
的区别,来自Ruby文档:
+
:返回一个新的字符串,其中包含将other_str连接到str后面的结果。
<<
:将给定对象连接到str。如果对象是介于0和255之间的Fixnum,则在连接之前将其转换为字符。<<
会直接更改原字符串,+
会返回新字符串,因此更占用内存),以及如果第一个操作数是Fixnum时的处理方式(<<
会添加与该数字代码相等的字符,+
会引发错误)。Pathname('/home/foo') + '/etc/passwd' # => #<Pathname:/etc/passwd>
。根据 rubydoc 的示例设计,这是有意而为之的。看来使用 File.join 更加安全。 - Kelvin(Pathname(ROOT_DIR) + project + 'App.config').to_s
。 - lacostenycoder#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
作为<<
的别名。
"foo" "bar" 'baz" #=> "foobarabaz"
。 - Boris Stitnicky以下是更多的方法:
"String1" + "String2"
"#{String1} #{String2}"
String1<<String2
And so on ...