首页 > 解决方案 > 为什么 ruby​​ 在创建一个类后会创建 3 个对象?

问题描述

我正在研究 Ruby 的元类。我读了这个答案,它很好地描述了元类是什么。它显示在那里,当创建一个类时,它将创建两个对象。这是可以理解的。一个用于类本身,一个用于它的元类。但是当我自己尝试时,我发现它正在创建三个对象。

puts "Before Class Creation object count - #{ObjectSpace.count_objects[:T_CLASS]}"
class Test
  def self.foo # test_singleton
    p 'Printed from method #foo'
  end

  def bar # test
    p 'Printed from method #bar'
  end
end
puts "After Class Creation object count - #{ObjectSpace.count_objects[:T_CLASS]}"

###############

Before Class Creation object count - 949
After Class Creation object count - 952

我正在使用Ruby - 2.5.1.

谁能帮我理解这个?

更新:

我添加的参考 SO帖子使用的是 ruby​​-1.9.1 或更高版本,因为方法count_objectsObjectSpace在 1.9.1 中引入的。似乎T_CLASS计数始终为 3(尝试使用ruby-1.9.3-p551)。

所以,到目前为止,为什么这个答案仍然是个谜。显微镜下的红宝石也说计数是 2。

标签: rubyruby-1.9.3

解决方案


来自https://bugs.ruby-lang.org/issues/16788

创建一个类会自动创建一个单例类(用户无法访问)。引用类的单例类会自动创建该单例类的单例类。这是为了保持元类继承结构的一致性。否则,类方法不会从超类的元类继承,这是必要的,因为超类的类方法应该可以作为子类的类方法使用。

稍微修改一下问题代码:

$old_classes = []
def print_objects
  new_classes = []
  ObjectSpace.each_object(Class){|x| new_classes << x}
  puts "New classes: #{new_classes - $old_classes}" unless $old_classes.empty?
  puts "Counts: #{ ObjectSpace.count_objects[:T_CLASS] }"
  $old_classes = new_classes
end

print_objects

class Test
end
puts 'Test class created'
print_objects

class Test
  def self.foo
  end 
end
puts 'Test singleton class referenced'
print_objects

我得到以下结果:

Counts: 690
Test class created
New classes: [Test]
Counts: 692
Test singleton class referenced
New classes: [#<Class:Test>]
Counts: 693

我在控制台内外使用 Ruby 2.6 和 2.0 进行了尝试(数字不同,但差异相同)和 @SajibHassan 使用 1.9.3(count_objects引入该方法的版本)。这意味着差异始终为 3,并且用户无法访问创建的第一个单例类。

Ruby Under a Microscope一书(写于 Ruby 2.1 发布后的 2012 年)也描述了仅创建两个元类,这与我们得到的结果不匹配。

请注意, Module#prepend@JörgWMittag 在评论中提到的方法(在 Ruby 2.0 中引入)是这个额外类的可能原因,使用T_ICLASS. 检查引入该方法的提交以获取详细信息。我想这T_ICLASS代表内部类,因此内部类不应该对用户可见(这是有道理的)。我不确定为什么有些T_CLASS用户可以访问,而有些则不能。


推荐阅读