在应用删除之前,我们应该在字符串中检查字符!()



这很琐碎,但已经使我烦恼了一段时间。

我有一个字符串:

x = 'abc/'

,要删除'/'令牌。

我知道这样做的最简单方法是:

x.delete!('/')

效果很好。检查对象ID:

x = 'abc/'
x.object_id     # => 90851540
x.delete!('/')
x.object_id     # => 90851540
x               # => "abc"

对象ID保持不变,所以我得出结论Ruby修改了x AS-IS,而无需生成新副本。

最好检查字符串是否实际上具有"/"字符将delete!()应用于它?

我记得有人曾经说过"没关系"由于delete!()无论如何都会检查给定的字符串,并且仅在字符串具有字符时进行修改。

这很公平。

,但我想知道两者的利弊方法。会:

if x.include? '/'

更快?会更好或更方便吗?

在代码中可能更清晰,但是也使代码更详细,也许也可能导致一些开销。

有时我单独使用delete!(),而无需任何检查,有时我会进行检查。

是比其他,因为现在我有点赞成"不检查",不是因为速度原因,而是因为由于语法/较少的代码。

我可能会选择delete!,而无需检查大多数时间("少代码"并且仍然清晰(,但让我们评估绩效:

test.rb

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)

基于此结果,我们看到(正如人们可能期望的(删除之前的检查(由于该额外检查(比仅删除 该字符串包含 /。但是,当不存在/时,首先检查速度要快得多。

因此,从性能的角度来看,如果您期望没有/的情况很高,则可能需要使用include?


如果您想知道A 50%/50%方案会是什么样,这是测试:

test.rb

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

结果

'/' PRESENT IN 50%
Rehearsal ----------------------------------------------
without if   0.540000   0.010000   0.550000 (  0.554114)
with if      0.410000   0.000000   0.410000 (  0.419098)
------------------------------------- total: 0.960000sec
                 user     system      total        real
without if   0.540000   0.000000   0.540000 (  0.549411)
with if      0.410000   0.000000   0.410000 (  0.420603)

我不会出于简单的原因检查它是多余的。即使我检查了令牌的存在,Ruby还是要再次检查它(无法跳过它(。我看到的一个问题是NIL检查,变量可能为零。在这种情况下,我也会做类似variable.to_s.delete!()的事情。因此,我认为我有足够的理由跳过检查/验证令牌的存在,并且没有理由进行防御编码。

最新更新