Ruby的模块包含机制

发表于:2014-3-19 11:37

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:言无不尽    来源:51Testing软件测试网采编

  首先,最外层的 while 循环对 module 的祖先链(ancestors)逐一遍历。对于每个 module,内层的 for 循环会检查 module 是否已经包含在 klass 的祖先链中,如果已经包含,则跳过,否则,把 module 插入到 c 和 c 的父类之间。
  在测试 module 是否已包含在祖先链的过程中,变量 superclass_seen 用来判断是否越过了一个非包含类,如果是,则不移动插入点。所以模块包含不会将模块插到祖先链中下一个非包含类之后。
  模块的插入工作是由第 31 行代码完成的,它调用 rb_include_class_new 函数为模块创建了一个包含类(include class),它以 c 的父类作为父类,接着又将这个包含类设置为 c 的父类。我们来看看 rb_include_class_new 函数是如何创建包含类的。
VALUE
rb_include_class_new(VALUE module, VALUE super)
{
VALUE klass = class_alloc(T_ICLASS, rb_cClass);
if (BUILTIN_TYPE(module) == T_ICLASS) {
module = RBASIC(module)->klass;
}
if (!RCLASS_IV_TBL(module)) {
RCLASS_IV_TBL(module) = st_init_numtable();
}
if (!RCLASS_CONST_TBL(module)) {
RCLASS_CONST_TBL(module) = st_init_numtable();
}
RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
RCLASS_M_TBL(klass) = RCLASS_M_TBL(RCLASS_ORIGIN(module));
RCLASS_SUPER(klass) = super;
if (RB_TYPE_P(module, T_ICLASS)) {
RBASIC(klass)->klass = RBASIC(module)->klass;
}
else {
RBASIC(klass)->klass = module;
}
OBJ_INFECT(klass, module);
OBJ_INFECT(klass, super);
return (VALUE)klass;
}
  第 4 行,class_alloc 创建了一个新类,并为它设置了 T_ICLASS 标识,有了这个标识,Ruby 就会认为它是一个包含类。接着就是一系列的初始化,将新类的内部表指向模块中对应的表。最后,将新类的 klass 指向模块,这样,包含类就创建完成了。
  第 17 行有个 RCLASS_ORIGIN 宏,我们来看看它的作用是什么,Ruby 源码中,该宏的定义如下:
  #define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin)
  可以看到,它指向一个类的 origin 成员。简单来说,它获取某个类的原始类。原始类跟模块前置有着密切的关系。关于模块前置的更多信息,请阅读《Ruby 中模块前置的实现》这篇文章。
  了解这些信息之后,我们来总结一下。为了便于描述,我们以文章开头的那段代码作为例子,来回顾一下模块包含的全过程。
  A = Module.new
  B = Module.new
  module C
  include A, B    # Inclusion is done by this line
  end
  当调用模块 C 的 include 方法时,默认实现 Module#include 会以相反的顺序对参数模块回调 append_features 和 included 方法。真正的包含逻辑在 Module#append_features 的内部实现。
  对每个被包含的模块,Ruby 会遍历其祖先链。对链上的每个模块,会首先检查是否已包含过,如果已包含,则跳过,否则为该模块创建一个包含类,插入到模块 C 的祖先链中。
  当然,以上的描述省略了一些细节,比如类型安全检查、对插入点的调整、检查循环包含、以及对 Refinement 的处理。如果读者有兴趣,可以参照源代码去理解。
  模块包含的本质是将被包含的模块的祖先链插入到另一个模块的祖先链中,其实最终,都是在维护一个祖先链。
33/3<123
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号