我正在研究 Ruby 的元类。我read this answer在那里很好地描述了元类是什么。它显示在创建一个类时它将创建两个对象。这是可以理解的。一种用于类本身,一种用于它的元类。但是当我自己尝试时,我发现它正在创建三个对象。
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
.谁能帮我理解这个?
更新:
reference SO我添加的帖子使用 ruby-1.9.1 或更高版本,作为方法
count_objects
为 ObjectSpace
在 1.9.1 中引入。看来T_CLASS
计数始终为 3(尝试使用 ruby-1.9.3-p551
)。所以,直到现在仍然是一个谜 this answer . Ruby under a microscope还说计数是 2。
最佳答案
来自 https://bugs.ruby-lang.org/issues/16788 :
Creating a class automatically creates a singleton class (which is not accessible to the user). Referencing the singleton class of a class automatically creates a singleton class of that singleton class. This is to keep consistency of the inheritance structure of metaclasses. Otherwise, class methods wouldn't inherit from the superclass's metaclass, which is necessary as the superclass's class methods should be available as the subclass's class methods.
稍微修改一下问题代码:
$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 (写于 2012 年 Ruby 2.1 发布后)也描述了只创建了两个元类,这与我们得到的结果不符。
注意像
Module#prepend
这样的方法(在 Ruby 2.0 中引入),@JörgWMittag 在评论中提到作为这个额外类的可能原因,使用 T_ICLASS
.查询 the commit in which the method was introduced详情。我猜是 T_ICLASS
代表内部类,因此内部类不应该对用户可见(这是有道理的)。我不知道为什么有些 T_CLASS
用户可以访问,而其他一些则不能。
关于ruby - 为什么 ruby 在创建一个类后会创建 3 个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61031735/