Rails 小白的填坑之路。
写在前面
前几天被老大问到merge与deep_merge的区别,一时语塞,试了几个例子,大致get到了两者的区别,但是当时没有记录下来,这里做一下笔记,加深印象。
正文
merge用法
在docs中搜索merge,可以看到有10个名为merge的method,这里我们要对比deep_merge,所以选择继承自Hash的ActiveSupport::HashWithIndifferentAccess下的method merge。
选自ActiveSupport::HashWithdifferentAccess
merge(hash, &block)
This method has the same semantics of
update
, except it does not modify the receiver but rather returns a new hash with indifferent access with the result of the merge.此处的merge不会修改当前对象,而是将合并后的结果以一个新的hash表格式返回。
其实这里的merge就等同于ruby中的merge, 对于两个hash,针对共有的key,默认取后一个hash的key对应的value。
看个例子:
h1 = { "a" => 100, "b" => 200 } h2 = { "b" => 254, "c" => 300 } h1.merge(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
你可以通过block来指定merge的规则:
h1 = { "a" => 100, "b" => 200 } h2 = { "b" => 254, "c" => 300 } h1.merge(h2) {|k,v1,v2| v1+v2} #=> {"a"=>100, "b"=>454, "c"=>300} h1.merge(h2) {|k,v1,v2| v1} #=> { "a" => 100, "b" => 200 }
deep_merge用法
官方给到的解释和例子是这样的:
deep_merge(other_hash, &block)
Returns a new hash with
self
andother_hash
merged recursively.返回一个新的hash, 将当前对象和其他的hash进行递归merge。
还是以上面的例子为例:
h1 = { "a" => 100, "b" => 200 } h2 = { "b" => 254, "c" => 300 } h1.deep_merge(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
同样,你也可以通过block来指定deep_merge的规则:
h1 = { "a" => 100, "b" => 200 } h2 = { "b" => 254, "c" => 300 } h1.deep_merge(h2) {|k,v1,v2| v1+v2} #=> {"a"=>100, "b"=>454, "c"=>300} h1.deep_merge(h2) {|k,v1,v2| v1} #=> { "a" => 100, "b" => 200 }
二者差异
从上面的例子看,似乎两者没有什么区别。
在非嵌套的hash表中,merge能做的,deep_merge也能做。
但是针对nested hash,两者就不一样了。
看个例子:
h1 = { a: true, b: { c: [1, 2, 3], x: [1, 2, 3] } } h2 = { a: false, b: { x: [3, 4, 5] } } h1.merge(h2) #=> {:a=>false, :b=>{:x=>[3, 4, 5]}} h1.deep_merge(h2) #=> {:a=>false, :b=>{:c=>[1, 2, 3], :x=>[3, 4, 5]}}
使用merge时,对于相同的key, 它不会去检查对应的value是不是一个hash,就是简单按照merge的规则返回value。
使用deep_merge,会检查同样的key,对应的value是不是都是hash,如果是, 则对这两个hash再次进行deep_merge,也就是返回{ c: [1, 2, 3], x: [1, 2, 3] }.deep_merge{ x: [3, 4, 5] }的结果,也就是概念中提到的递归merge。
再看个例子:
h1 = { a: true, b: { c: [1,2,3], x: { y: 1 } } } h2 = { a: false, b: { x: { y: 2, z: 1} } } h1.deep_merge(h2) #=> {:a=>false, :b=>{:c=>[1, 2, 3], :x=>{:y=>2, :z=>1}}}
从上面这个例子可以看出,针对共有的key,deep_merge会一直检查对应的value是否都是hash,如果是,则继续对hash进行deep_merge,直到没有hash进行merge为止。
小结
针对非嵌套的hash:merge和deep_merge并没有什么差异。
针对嵌套的hash: 针对相同的key,merge不会检查,直接处理,根据merge规则返回value,deep_merge则会一直检查对应的value是否都是hash,如果是,则继续对hash进行deep_merge,直到没有hash进行merge为止。