为什么相同的表达式(hash2.keep_if {| k,v | k})会返回不同的值?

时间:2015-06-30 17:34:35

标签: ruby hash

考虑命令序列:

hash1 = {1 => "a" , 2 => "b" , 3 => "c" , 4 => "d"}
hash2 = {3 => "hello", 4 => "world" , 5 => "welcome"}

hash2.keep_if { |k, v| k }
=> {3=>"hello", 4=>"world", 5=>"welcome"}

hash2.keep_if { |k, v| hash1.key? k }
=> {3=>"hello", 4=>"world"}

hash2.keep_if { |k, v| k }
=> {3=>"hello", 4=>"world"}

为什么hash2.keep_if { |k, v| k }评估是截然不同的?我永远不会期待最后的结果!为什么会这样?

3 个答案:

答案 0 :(得分:3)

虽然没有以!结尾,但Hash#keep_if是一种破坏性方法,即它修改了Hash对象。 (另见Hash#select!

在您的示例中,hash2.keep_if { |k, v| hash1.key? k }会从5=>"welcome"中删除hash2部分。

答案 1 :(得分:1)

因为hash2在第二行被改变了(礼貌keep_if)。这里:

hash2
# => {3=>"hello", 4=>"world", 5=>"welcome"}
hash2.keep_if { |k, v| hash1.key? k }
# => {3=>"hello", 4=>"world"}

hash2
# => {3=>"hello", 4=>"world"}

如果您阅读keep_if的官方文档,则可以看到其状态:

  

删除给定块计算结果的self的每个元素   假的。

这意味着self本身会被改变。这导致了结果的差异。

答案 2 :(得分:1)

这是无意中使用就地修饰符的经典案例。 Hash#keep_if改变原始哈希。

hash2 = {3 => "hello", 4 => "world" , 5 => "welcome"}

hash2.keep_if { |k, v| k }
# Unmodified since the test does not exclude.

hash2.keep_if { |k, v| hash1.key? k }
# Permanently deletes key `5`

hash2
# => => {3=>"hello", 4=>"world"}

虽然许多就地修饰符很容易通过在名称的末尾包含!来发现,例如sub!gsub!,但有一些不提供任何线索,例如shiftpop。要确定您的通话会产生什么影响,如果您不熟悉该方法,请务必查阅文档。