题
我正在观看prag dave的第一个红宝石元编程截屏视频。在某些时候,他说当你向一个实例变量添加一个方法时,ruby会引入'ghost classes'。岛
animal = "cat"
def animal.speak
puts "hola"
end
animal.speak # => hola
animal.class # => String
dog = "dog"
dog.speak # Undefined method `speak' for "dog":String
String.send :speak # NoMethodError: undefined method `speak' for String:Class
animal.send :speak # hola
说话方法商店真的在哪里? 如果它是一个不可见的代理类,我们如何访问该代理类?
解决方案
方法 speak
存储在元类(也称为本征类)中,你称之为“不可见代理类”。在Ruby中,实例变量没有地方存储方法。它们只能存储实例变量及其类。因此,当您向实例添加方法时,会创建元类并将其插入到其类链中。为了更好地理解内部,我建议这篇文章来自Klank Boom Klang。
为了获得元类,您可以执行以下操作:
animal = "cat"
def animal.speak
puts "hola"
end
animal.speak # => hola
animal.class # => String
metaclass = class << animal; self; end
metaclass.inspect # => #<Class:#<String:0x2c9c460>>
metaclass.instance_methods.index 'speak' # => 102
metaclass.class # => Class
其他提示
有些人称它为“Singleton Class”
singleton_class = class << animal; self; end
实际上这个单例类是任何类的类方法的主机,请查看此示例,首先通过使用类方法'hi'和'bye'定义类Foo:
class Foo
def self.hi ; p "hi" ; end
def self.bye ; p "bye" ; end
end
Foo.singleton_methods #=> ["hi","bye"]
现在让我们定义一个为我们返回单例类的方法:
class Object
def singleton_class
class << self
self
end
end
end
现在试试这个:
Foo.singleton_methods #=> ["bye", "hi"]
Foo.singleton_class.instance_methods(false) #=> ["bye", "hi"]
不隶属于 StackOverflow