任何人都可以解释中提到的(子)类的存在 主题?
缺少文档
标识符中断类/常量命名规则。它以小写字母开头,但应以大写字母开头。
虽然存在,但标准方式无法访问 注册:
_
Rational::constants false
# [:compatible]
Rational::compatible
# NoMethodError: undefined method 'compatible' for Rational:Class
Rational::const_get 'compatible'
# NameError: wrong constant name compatible
感谢。
答案 0 :(得分:4)
我相信这个类的存在是为了Marshal向后兼容旧版本的Ruby。换句话说,它使得在一个版本的Ruby中Marshal.load
可以加载在旧版本的Ruby中编组的复杂和Rational对象。
您可以在第二行(line 2,446 in rational.c
)看到Rational :: compatible类的定义位置:
rb_define_private_method(rb_cRational, "marshal_dump", nurat_marshal_dump, 0);
compat = rb_define_class_under(rb_cRational, "compatible", rb_cObject);
rb_define_private_method(compat, "marshal_load", nurat_marshal_load, 1);
rb_marshal_define_compat(rb_cRational, compat, nurat_dumper, nurat_loader);
我的C很糟糕,但对我而言,这四行看起来分别如下:
Rational#marshal_dump
私有方法定义为指向C函数nurat_marshal_load
的指针。compatible
类(Rational
)下的rb_cRational
类。我认为第三个参数rb_cObject
是超类。Rational#marshal_load
定义为C函数nurat_marshal_dump
。rb_marshal_define_compat
:Rational类(rb_cRational
);刚刚定义的Rational :: compatible类(compat
);以及nurat_dumper
和nurat_loader
。从同一文件中的line 1,629开始,您可以看到nurat_dumper
和nurat_loader
(以及nurat_marshal_dump
和nurat_marshal_load
)的定义位置。使用git blame
的魔力,我们可以确切地看到nurat_dumper
和nurat_loader
的定义时间:2012年7月25日在Subversion中提交#36538。这是提交消息:
complex.c,rational.c:兼容的编组加载程序
complex.c
,rational.c
:与1.8兼容的兼容编组加载程序。 [ruby-core:45775] [Bug#6625]
现在我们到了某个地方! Bug #6625就是这个:
在复杂和理性
上破坏了元帅的兼容性由1.8或更早版本转储的Complex和Rational无法由trunk加载。
它继续描述一个测试用例,并包含上面提交中看到的补丁。
那么,也许你想知道的是rb_marshal_define_compat
?你可以看到它defined in marshal.c
。就像我说的那样,我的C很糟糕,但我认为它的作用是把它的参数 - newclass
(即Rational),oldclass
(Rational :: compatible),dumper
和{{ 1}} - 进入marshal_compat_t
struct并将其插入loader
。稍后,当您尝试compat_allocator_tbl
或Marshal.dump
对象时,它将在该表中查看是否存在兼容性类,并在必要时使用其“dumper”或“loader”。 p>
至于为什么Rational :: compatible没有以大写字母命名并且无法通过常规方式访问,我只能猜测这是设计使得它只能由Ruby在内部访问。
但是,您可以使用ObjectSpace获取对该类的引用,但您无法使用它:
Marshal.load