Ruby 中使用的大多数实例方法都是全局方法。这意味着它们在定义它们的类的所有实例中都可用。相反,单例方法是在单个对象上实现的。
有明显的矛盾。Ruby 将方法存储在类中,所有方法都必须与一个类相关联。定义单例方法的对象不是类(它是类的实例)。如果只有类可以存储方法,那么对象如何存储单例方法?创建单例方法时,Ruby 会自动创建一个匿名类来存储该方法。这些匿名类称为元类,也称为单例类或特征类。单例方法与元类相关联,而元类又与定义了单例方法的对象相关联。
如果在单个对象中定义了多个单例方法,则它们都存储在同一个元类中。
class Zen
end
z1 = Zen.new
z2 = Zen.new
def z1.say_hello # Notice that the method name is prefixed with the object name
puts "Hello!"
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
在上面的示例中,say_hello 方法是在 Zen 类的 z1 实例中定义的,而不是在 z2 实例中定义的。
以下示例显示了定义单例方法的不同方法,但结果相同。
class Zen
end
z1 = Zen.new
z2 = Zen.new
class << z1
def say_hello
puts "Hello!"
end
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
在上面的例子中,class << z1 改变了当前的 self 指向 z1 对象的元类;然后,它在元类中定义 say_hello 方法。
上述两个示例都用于说明单例方法的工作原理。但是,有一种更简单的方法来定义单例方法:使用名为 define_singleton_method 的内置方法。
class Zen
end
z1 = Zen.new
z2 = Zen.new
z1.define_singleton_method(:say_hello) { puts "Hello!" }
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
我们之前了解到,类也是对象(称为 Class 的内置类的实例)。我们还学习了类方法。类方法只不过是与类对象关联的单例方法。
再举一个例子:
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
所有对象都可能有元类。这意味着类也可以有元类。在上面的示例中, class << self 修改了 self ,因此它指向 Zabuton 类的元类。当一个方法在没有显式接收者(将在其上定义该方法的类/对象)的情况下定义时,它被隐式定义在当前范围内,即 self 的当前值。因此,stuff 方法是在 Zabuton 类的元类中定义的。上面的例子只是定义类方法的另一种方式。
在这篇关于 Ruby 类的文章中阅读更多内容。