我刚开始学习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是一种更短的方法。
为什么我应该使用一种格式而不是另一种格式?
答案 0 :(得分:70)
每当TIMTOWTDI(有多种方法)时,你应该寻找利弊。使用“字符串插值”(第二个)而不是“字符串连接”(第一个):
<强>优点:强>
to_s
<强>缺点:强>
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#format
和String#+
,因为它是我所知道的在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