奇怪的行为:哈希的键取消动态方法定义

mxg*_*grn 2 ruby hash metaprogramming

假设我想要一些String的实例与其他"普通"实例的行为不同 - 例如取消"upcase"方法的效果.我做以下事情:

class String
  def foo
    def self.upcase
      self
    end
    self
  end
end
Run Code Online (Sandbox Code Playgroud)

它似乎工作正常,我需要它的方式:

puts "bar".upcase #=> "BAR"
puts "bar".foo.upcase #=> "bar"
Run Code Online (Sandbox Code Playgroud)

但是,只要我使用String的欺骗实例作为Hash的键,行为开始对我来说很奇怪:

puts ({"bar".foo => "code"}).keys.first.upcase #=> "BAR", not "bar"!
Run Code Online (Sandbox Code Playgroud)

...就好像忽略了foo方法,并将String的原始实例用作键.

任何人都可以看到这里发生了什么?谢谢你!

Eli*_*Eli 5

Ruby的Hash有一个特殊的例子,它使用字符串作为哈希键 - 它创建了字符串的内部副本.

基本上它是为了保护您不使用字符串(对象)作为键,然后在代码中稍后更改该字符串对象,这可能会导致一些令人困惑的情况.可变键变得棘手.

而不是将方法修改为返回更改的字符串类的字符串,我只是创建一个新的字符串子类,它会覆盖upcase然后只设置它的值.