假设我想要一些String的实例与其他“普通”实例的行为不同 - 例如取消“upcase”方法的效果。我做了以下事情:
class String
def foo
def self.upcase
self
end
self
end
end
似乎工作正常,我需要的方式:
puts "bar".upcase #=> "BAR"
puts "bar".foo.upcase #=> "bar"
但是,只要我使用String的欺骗实例作为Hash的键,行为开始对我来说很奇怪:
puts ({"bar".foo => "code"}).keys.first.upcase #=> "BAR", not "bar"!
...就好像忽略了foo方法,并将String的原始实例用作键。
任何人都可以看到这里发生了什么?非常感谢!
答案 0 :(得分:5)
Ruby的Hash有一个使用字符串作为哈希键的特殊情况 - 它是字符串的内部副本。
基本上,它是为了保护您不使用字符串(对象)作为键,然后在代码中稍后更改该字符串对象,这可能会导致一些令人困惑的情况。可变键变得棘手。
不是将方法修改为返回更改的字符串类的字符串,而是创建一个新的字符串子类,它会覆盖upcase然后只设置它的值。
答案 1 :(得分:0)
在Ruby中扩展单个对象的常用方法是:
s = "bar"
class<<s
def self.upcase
self
end
end
...但这并不能解决您的问题。似乎Ruby对作为字符串的哈希键或字符串的子类具有特殊规则,而不是字符串,您可以使用具有有意义的to_s
定义的对象吗?
答案 2 :(得分:0)
因为在Ruby中你可以重新打开核心类并虚拟地重新定义所有内容,但这并不意味着你应该这样做。
强大的权力带来了巨大的责任,你的责任就是不再重新定义核心库方法,因为有几个对象可能需要它。 如果您的实例行为不像Sting,则声明您自己的类并扩展String。