ruby - 为什么 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_objects
是ObjectSpace
在 1.9.1 中引入的。似乎T_CLASS
计数始终为 3(尝试使用ruby-1.9.3-p551
)。
解决方案
来自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
用户可以访问,而有些则不能。
推荐阅读
- python - 在图像中组合水平对齐的多边形
- c - AVL比较方法,正确的方法与否?
- rest - com.sun.enterprise.admin.remote.RemoteFailureException
- c# - 电子邮件确认:UserManager.ConfirmEmailAsync 错误:名称不能为空或为空
- rust - 如何确保我的函数将收到有效长度的 Vec?
- android - 在移动网站的二维码阅读器中打开后置摄像头
- c# - 通过按特定标签拆分字符串来获取字符串列表
- python - python中以下代码的时间复杂度是多少?
- ios - 旋转景观 collectionView
- python - 尝试访问 Select Input Python Splinter 时元素不可见