2

!Ruby で作業しているときに、値の代入としてメソッドを使用するか、通常のメソッドを使用するかで競合することがよくあります。いつ何を使うかわかりません。たとえば、2 つのハッシュ (h1 と h2) があり、それらをマージして値をハッシュ h1 に格納したい場合、or を使用する 必要がありますh1.merge!(h2)h1 = h1.merge(h2)?

両者に違いはありますか?

4

3 に答える 3

7

ほとんどの場合、 と の間にほとんど違いはありませh1.merge!(h2)h1 = h1.merge(h2)

ただし、次の点に注意してください。

は古いハッシュを変更するためmerge!、同じハッシュへの参照を保持するプログラム内の他のオブジェクトに意図せず影響を与える可能性があります。メソッド パラメーターとして受け取ったハッシュを変更することは、通常、呼び出し元が想定していないため、不適切な方法です。

merge!あなたがそのファンなら、使用は関数型プログラミングではありません。

merge!特に大きなハッシュの場合、新しいハッシュを作成しないため、を使用する方がおそらく効率的です。

私はmergeほとんどの場合使用merge!し、安全で優れていると判断した場合にのみ使用します.

于 2013-09-15T18:01:07.077 に答える
2

両者に違いはありますか?

はい、もちろんあります。

受信機自体を変更したい場合は、!(bang) バージョンを使用する必要があります。Hash#merge

h1 = {a: 1}
h2 = {b: 2}
h3 = h1.merge(h2) # => {:a=>1, :b=>2}
h1 # => {:a=>1}

今見てください:

h1 = {a: 1}
h2 = {b: 2}
h1.merge!(h2) # => {:a=>1, :b=>2}
h1 # => {:a=>1, :b=>2}

h1 = h1.merge(h2) は同じ答えを返します

うーん、それは、メソッドh1を適用した後に新しいハッシュを割り当てているためです。Hash#merge

h1 = {a: 1}
h2 = {b: 2}
h1.object_id # => 69435570
h1 = h1.merge(h2) # => {:a=>1, :b=>2}
h1 # => {:a=>1, :b=>2}
h1.object_id # => 69434820

あなたが言ったように、それらをマージして値をハッシュ h1 に保存したいので、使用するHash#merge!ことをお勧めします。h1 = h1.merge(h2)h1.merge!(h2)h1

于 2013-09-15T17:47:37.107 に答える
2

Ruby で作業していると、! を使用したメソッドの使用が競合することがよくあります。または通常の方法を使用します。

もっと重要なことを考えるべきなので、ルールを採用してください: bang メソッドは絶対に使用しません。今、自由になり、舞い上がる...

require 'benchmark'

n = 1_000_000

h1 = {a: 1, b: 2}
h2 = {b: 3, c: 4}

Benchmark.bm(20) do |b|
  b.report("no-bang-hash-merge") do
    n.times { h1 = h1.merge h2 }
  end

  b.report("bang-hash-merge") do
    n.times { h1.merge! h2 }
  end
end

--output:--
                          user     system      total        real
no-bang-hash-merge     2.750000   0.050000   2.800000 (  2.817345)
bang-hash-merge        0.400000   0.000000   0.400000 (  0.406870)

.

require 'benchmark'

hash_size = 10_000

#Keys overlap:
key1 = 'a'
key2 = nil

h1 = {}
hash_size.times do |i|
  h1[key1] = i
  key2 = key1.dup if i == hash_size/2
  key1.succ!
end


h2 = {}
hash_size.times do |i|
  h2[key2] = i
  key2.succ!
end

=begin
#No overlap:
key = 'a'

h1 = {}
hash_size.times do |i|
  h1[key] = i
  key.succ!
end


h2 = {}
hash_size.times do |i|
  h2[key] = i
  key.succ!
end
=end

n = 100_000

puts "50% of keys overlap, hash size #{hash_size}:"
Benchmark.bm(20) do |b|
  b.report("no-bang-hash-merge") do
    n.times { h1 = h1.merge h2 }
  end

  b.report("bang-hash-merge") do
    n.times { h1.merge! h2 }
  end
end

--some test runs:---

50% of keys overlap, hash size 10000:
                           user     system      total        real
no-bang-hash-merge   1500.570000  74.520000 1575.090000 (1695.523240)
bang-hash-merge      255.910000   0.940000 256.850000 (269.957178)



No keys overlap, hash size 10000:
                           user     system      total        real
no-bang-hash-merge   1906.070000 109.340000 2015.410000 (2151.865636)
bang-hash-merge      162.680000   0.190000 162.870000 (163.369607)

スピードが必要な場合は、強打してください。それ以外の場合は、危険を冒さないでください。

于 2013-09-15T18:22:40.840 に答える