考虑命令序列:
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 }
评估是截然不同的?我永远不会期待最后的结果!为什么会这样?
答案 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!
,但有一些不提供任何线索,例如shift
和pop
。要确定您的通话会产生什么影响,如果您不熟悉该方法,请务必查阅文档。