这是相当微不足道的,但已经让我误解了很长一段时间。
我有一个字符串:
x = 'abc/'
并希望删除' /'令牌。
我所知道的最简单的方法是:
x.delete!('/')
工作正常。检查对象ID:
x = 'abc/'
x.object_id # => 90851540
x.delete!('/')
x.object_id # => 90851540
x # => "abc"
对象id保持不变,所以我得出结论
Ruby原样修改了x
,没有生成新副本。
检查字符串是否真的有' /'是否更好?首先是人物角色
将delete!()
应用于它?
我记得有人曾经说过"没关系"
因为delete!()
无论如何都会检查给定的String,
并且只有在字符串中包含字符时才进行修改。
这很公平。
但我想知道两者的利弊 做法。将:
if x.include? '/'
更快?会更好还是更方便?
在代码中它可能更清晰,但它 也使代码更冗长,也许它 也可能导致一些开销。
有时我单独使用delete!()
,没有任何检查,有时我会进行检查。
有一种方式比 另外,因为现在我稍微赞成 "没有,如果检查",不是因为速度原因而是在很大程度上 因为语法较少/代码较少。
答案 0 :(得分:3)
我可能会在没有检查大部分时间的情况下使用delete!
(“更少的代码”并且仍然清晰),但我们可以评估性能:
require 'benchmark'
iterations = 1_000_000
puts "'/' ALWAYS PRESENT"
Benchmark.bmbm do |bm|
bm.report('without if') do
iterations.times do
x = "abc/"
x.delete!("/")
end
end
bm.report('with if') do
iterations.times do
x = "abc/"
x.delete!("/") if x.include?("/")
end
end
end
puts "\n'/' NEVER PRESENT"
Benchmark.bmbm do |bm|
bm.report('without if') do
iterations.times do
x = "abc"
x.delete!("/")
end
end
bm.report('with if ') do
iterations.times do
x = "abc"
x.delete!("/") if x.include?("/")
end
end
end
'/' ALWAYS PRESENT
Rehearsal ----------------------------------------------
without if 0.540000 0.000000 0.540000 ( 0.541003)
with if 0.630000 0.010000 0.640000 ( 0.632728)
------------------------------------- total: 1.180000sec
user system total real
without if 0.510000 0.000000 0.510000 ( 0.513438)
with if 0.630000 0.000000 0.630000 ( 0.632055)
'/' NEVER PRESENT
Rehearsal ----------------------------------------------
without if 0.510000 0.000000 0.510000 ( 0.513233)
with if 0.190000 0.000000 0.190000 ( 0.194709)
------------------------------------- total: 0.700000sec
user system total real
without if 0.510000 0.000000 0.510000 ( 0.514632)
with if 0.180000 0.000000 0.180000 ( 0.186374)
基于这个结果,我们看到(正如人们所料),删除之前的检查有点慢(由于额外的检查),而不仅仅是删除当字符串包含{{1 }}。但是,当/
不存在时,首先检查要快得多。
因此,从性能的角度来看,如果您预计没有/
的案例比例较高,则可能需要使用include?
。
如果您想知道 50%/ 50%情景会是什么样子,这就是测试:
/
require 'benchmark'
iterations = 500_000
puts "\n'/' PRESENT IN 50%"
Benchmark.bmbm do |bm|
bm.report('without if') do
iterations.times do
x = "abc/"
x.delete!("/")
end
iterations.times do
x = "abc"
x.delete!("/")
end
end
bm.report('with if ') do
iterations.times do
x = "abc/"
x.delete!("/") if x.include?("/")
end
iterations.times do
x = "abc"
x.delete!("/") if x.include?("/")
end
end
end
答案 1 :(得分:1)
我不会检查原因,这是多余的。
即使我检查令牌存在,ruby无论如何都会再次检查它(并且无法跳过它)。
我看到的一个问题是零检查,变量可能是零。在那种情况下,我会做variable.to_s.delete!()
之类的事情。
因此,我认为我有足够的理由跳过检查/验证令牌的存在,我没有理由做出防御性编码。