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 - selfand- other_hashmerged 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为止。