Ruby: 单例类真的是自己的匿名类吗?

Ruby: Are singleton classes really own anonymous classes?

Programming Ruby 1.9 & 2.0一书的24.2 Singletons一章中,给出了以下代码:

animal = "cat"
def animal.speak
  puts "The #{self} says miaow"
end

并解释为:"When we defined the singleton method for the "cat" 对象,Ruby 创建了一个新的匿名 class 并定义了 class 中的 speak 方法。这个匿名 class 称为 单例 class(有时 本征class)."

不幸的是,我无法验证 Ruby (2.5.1) 实际上创建了自己的匿名 class:

str = "a string"                 # => "a string"
[str, str.object_id]             # => ["a string", 47279316765840]
[str.class, str.class.object_id] # => [String, 47279301115420]

def str.greet
  "hello"
end                              # => :greet

str.greet                        # => "hello"

[str, str.object_id]             # => ["a string", 47279316765840]
[str.class, str.class.object_id] # => [String, 47279301115420]

从上面可以看出,str的class在定义单例方法greet后并没有改变:它仍然显示为 String 与相同的 object_id 47279301115420.

那么,匿名 class 在哪里?

str = "a string"                 # => "a string"
[str, str.object_id]             # => ["a string", 47279316765840]
[str.class, str.class.object_id] # => [String, 47279301115420]

def str.greet
  "hello"
end                              # => :greet

str.greet                        # => "hello"
当您询问 str.class 或查看祖先链 (str.class.ancestors) 时,

Ruby 隐藏了 eigenclass。但是,您可以通过在使用 <<

检查 class 后返回 self 来获取对 eigenclass 的引用
str_class = class << str
  self
end
# => #<Class:#<String:0x007fbba28b3f20>>

str_class.instance_methods(false) #=> [:greet] # the singleton method you defined becomes the instance method of this eigenclass. :)

str_class.ancestors
[#<Class:#<String:0x007fbba28b3f20>>, String, Comparable, Object, Kernel, BasicObject]