我正在寻找一种更优雅的方式来连接Ruby中的字符串.
我有以下几行:
source = "#{ROOT_DIR}/" << project << "/App.config"
这样做有更好的方法吗?
就此而言,<<
和之间的区别是+
什么?
您可以通过以下几种方式实现:
如你所示,<<
但这不是通常的方式
使用字符串插值
source = "#{ROOT_DIR}/#{project}/App.config"
同 +
source = "#{ROOT_DIR}/" + project + "/App.config"
第二种方法在内存/速度方面似乎比我看到的更有效(虽然没有测量).当ROOT_DIR为零时,所有三种方法都会抛出未初始化的常量错误.
处理路径名时,您可能希望使用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"
如果您只是连接路径,则可以使用Ruby自己的File.join方法.
source = File.join(ROOT_DIR, project, 'App.config')
来自http://greyblake.com/blog/2012/09/02/ruby-perfomance-tricks/
使用<<
aka concat
远比使用aka 更有效+=
,因为后者创建一个时态对象并用新对象覆盖第一个对象.
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'] * '/'
这是另一个受这个要点启发的基准.它比较动态和预定义字符串的concatenation(+
),appending(<<
)和interpolation(#{}
).
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中的插值很重.
我更喜欢使用路径名:
require 'pathname' # pathname is in stdlib Pathname(ROOT_DIR) + project + 'App.config'
关于<<
和+
红宝石文档:
+
:返回一个新的 String,其中包含连接到str的other_str
<<
:将给定对象连接到str.如果对象是0到255之间的Fixnum,则在连接之前将其转换为字符.
所以区别在于第一个操作数变为什么(<<
进行了更改,+
返回新的字符串,因此内存更重),如果第一个操作数是Fixnum将会是什么(<<
将添加好像是代码等于该数字的字符,+
将会提高错误)
让我向你展示我的所有经验.
我有一个返回32k记录的查询,对于每个记录,我调用一种方法将该数据库记录格式化为格式化字符串,然后将其连接成一个字符串,在所有这个过程结束时将转换为磁盘中的文件.
我的问题是,据记录,大约24k,连接字符串的过程导致痛苦.
我正在使用常规的'+'运算符.
当我改为'<<'时就像魔术一样.真的很快.
所以,我记得我的旧时代 - 有点像1998年 - 当我使用Java并使用'+'连接String并从String更改为StringBuffer时(现在我们Java开发人员拥有StringBuilder).
我相信Ruby世界中+/<<的过程与Java世界中的+/StringBuilder.append相同.
第一个在内存中重新分配整个对象,另一个只是指向一个新地址.
以下是更多方法:
"String1" + "String2" "#{String1} #{String2}" String1<等等 ...
10> Boris Stitni..:连说你说?怎么样的
#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"`