[Active Support 原始碼閱讀解析] Hash reverse_merge 以及 reverse_merge! method

平常我們寫 Ruby 時,如果要合併兩個 hash 且遇到相同的 key 時會以某個 hash 的 key 值為主要依據的話,Ruby 內建的 merge 以及 merge! 便非常適用,而 Active Support 替 Hash 另外增加了 reverse_merge 以及 reverse_merge! 這兩個 method,讓你在某些情境寫 mergemerge! 可能沒有那麼直觀時,可以有個替代方案。

merge 與 merge! 使用說明

merge

傳回一個包含 hsh 以及 other_hash 內容的「新」hash,若沒有指定 block ,key 相同的部分,無條件以 other_hash 的值為主。

用例子說明:

hsh = { "a" => 100, "b" => 200 }
other_hash = { "b" => 254, "c" => 300 }
hsh.merge(other_hash)   #=> {"a"=>100, "b"=>254, "c"=>300}

puts hsh #=> { "a" => 100, "b" => 200 }

使用 merge ,原本的內容並不會有所更動。

merge!

把 other_hash 的內容添加到 hsh 當中。如果沒有指定 block 的話,key 相同的部分,無條件以 other_hash 的值覆蓋掉原來 hsh 的值。如果有指定 block ,就會由 block 的內容來決定,呼叫 block 的參數分別為「key」、「hsh 裡面這個 key 的值」以及「other_hash 裡面這個 key 的值」。

用例子說明:

hsh = { "a" => 100, "b" => 200 }
other_hash = { "b" => 254, "c" => 300 }
hsh.merge!(other_hash)   #=> {"a"=>100, "b"=>254, "c"=>300}

puts hsh #=> {"a"=>100, "b"=>254, "c"=>300}
puts other_hash #=> { "b" => 254, "c" => 300 }

我們可以觀察到,hsh 的內容改變了,但是 other_hash 的內容依然不變。

我們再來看一個例子,不過這次有加上 block :

hsh = { "a" => 100, "b" => 200 }
other_hash = { "b" => 254, "c" => 300 }
hsh.merge!(other_hash) { |key, v1, v2| v1 }  #=> {"a"=>100, "b"=>200, "c"=>300}

在 block 中,我們指定如果 key 相同的話,無條件選擇 hsh 的值,因此可以發現執行 hsh.merge! 後的結果跟上一個例子不同。

解析原始碼

原始碼的位置在這裡: active_support/core_ext/hash/reverse_merge.rb

class Hash
  def reverse_merge(other_hash)
    other_hash.merge(self)
  end

  def reverse_merge!(other_hash)
    # right wins if there is no left
    merge!( other_hash ){|key,left,right| left }
  end
  alias_method :reverse_update, :reverse_merge!
end

首先我們來看 reverse_merge 這個 method ,可以發現它只是很簡單地傳回一個「新」 hash ,如果兩個 hash 有相同的 key,無條件以呼叫者的值為主,也就是說,原本我們用 merge 是這樣寫的 code :

hsh.merge(other_hash)

便可以寫成:

other_hash.reverse_merge(hsh)

看到 reverse_merge! 你或許會困惑為什麼不要直接這樣寫就好了:

def reverse_merge!(other_hash)
  other_hash.merge!(self)
end

但是請注意:呼叫 merge! 這個 method 的 hash 本身會改變!因此如果這樣寫,到最後內容有更動的並不是呼叫 reverse_merge! 的 hash 本身,而是被當作參數的 other_hash。

看到這裡你會發現,設計這兩個 method 的用途只是把「主要依據者」從後面的位置改到前面而已。

comments powered by Disqus
分享至 Facebook 分享至 Google +