Ruby元类:为什么三个定义单例方法时?
让我们计算MRI范围内的类:
def count_classes ObjectSpace.count_objects[:T_CLASS] end k = count_classes 使用类方法定义类: class A def self.foo nil end end 并运行: puts count_classes - k #=> 3 请解释一下,为什么三个? 解决方法
看看MRI代码,每当你创建一个在Ruby中是Class类型对象的类时,ruby会自动为该新类创建“元类”类,这是另一个单例类型的Class对象.
C函数调用(class.c)是: rb_define_class rb_define_class_id rb_class_new(super); rb_make_metaclass(klass,RBASIC(super)->klass); 因此,每次定义一个新类时,Ruby都会定义另一个带有元信息的类. 当你定义一个类方法时,我的意思是,def self.method,在内部,ruby调用rb_define_singleton_method.您可以检查它是否执行以下步骤: 创建一个ruby文件test.rb: class A def self.foo end end 并运行以下命令: ruby --dump insns test.rb 您将获得以下输出: == disasm: <RubyVM::InstructionSequence:<main>@kcount.rb>=============== 0000 trace 1 ( 70) 0002 putspecialobject 3 0004 putnil 0005 defineclass :A,<class:A>,0 0009 leave == disasm: <RubyVM::InstructionSequence:<class:A>@kcount.rb>============ 0000 trace 2 ( 70) 0002 trace 1 ( 71) 0004 putspecialobject 1 0006 putself 0007 putobject :foo 0009 putiseq foo 0011 opt_send_simple <callinfo!mid:core#define_singleton_method,argc:3,ARGS_SKIP> 0013 trace 4 ( 73) 0015 leave ( 71) == disasm: <RubyVM::InstructionSequence:foo@kcount.rb>================== 0000 trace 8 ( 71) 0002 putnil 0003 trace 16 ( 72) 0005 leave define_singleton_method映射到rb_obj_define_method C函数(object.c),它执行以下调用: rb_obj_define_method rb_singleton_class(obj) rb_mod_define_method 函数rb_singleton_class公开了在定义类时创建的元类,但它也为此元类创建了一个新的元类. 根据这个函数的Ruby文档:“如果一个obj是一个类,返回的单例类也有自己的单例类,以保持元类的继承结构的一致性”. 这就是为什么在定义类方法时类的数量增加1的原因. 如果通过以下方式更改代码,则会发生相同的效果 class A end A.singleton_class singleton_class映射到rb_obj_singleton_class C函数,该函数调用rb_singleton_class. 即使您创建了一个类方法并调用了singleton_class方法,创建的类的数量也不会改变,因为已经创建了处理元信息所需的所有类.例: class A def self.foo nil end end A.singleton_class 上面的代码将继续返回3. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |