Ste*_*fan 3 ruby class include
我试图了解一些 Ruby 的内部结构:
尝试使用include
类而不是模块会导致TypeError
:(这是设计使然的)
class C
end
class Foo
end
Foo.include(C)
#=> TypeError: wrong argument type Class (expected Module)
Run Code Online (Sandbox Code Playgroud)
我想知道类型检查“在幕后”是如何工作的。
由于类是模块,我假设 Ruby 检查参数是否是以下的实际实例Module
:
C.is_a?(Module) #=> true
C.instance_of?(Module) #=> false
Run Code Online (Sandbox Code Playgroud)
听起来很合理,不是吗?
但是当我定义自己的Module
子类并创建该子类的实例时,它工作得很好:
class Klass < Module
end
K = Klass.new
Foo.include(K)
# no error
Run Code Online (Sandbox Code Playgroud)
但K
是 的一个实例Klass
,就像C
是 的一个实例一样Class
。并且Klass
是 的子类Module
,就像Class
:
K.is_a?(Module) #=> true
K.instance_of?(Module) #=> false
K.class #=> Klass
C.class #=> Class
Klass.superclass #=> Module
Class.superclass #=> Module
Run Code Online (Sandbox Code Playgroud)
那么该类型签入include
实际上做了什么?
是否有一个隐藏属性可以让 Ruby 区分模块和类?
由于这是特定于实现的:我对 YARV/MRI 特别感兴趣。
正如@Stefan 评论的那样,Module#include
调用宏Check_Type(module, T_MODULE)
。您可以在https://ruby-doc.org/core-2.6/Module.html#method-i-include中找到它
进一步挖掘源码,可以发现头文件ruby.h中有一行
#define Check_Type(v,t) rb_check_type((VALUE)(v),(t))
Run Code Online (Sandbox Code Playgroud)
soCheck_Type
只是 的一个方便的别名,您可以在error.crb_check_type
中找到 的定义:rb_check_type
void
rb_check_type(VALUE x, int t)
{
int xt;
if (x == Qundef) {
rb_bug(UNDEF_LEAKED);
}
xt = TYPE(x);
if (xt != t || (xt == T_DATA && RTYPEDDATA_P(x))) {
unexpected_type(x, xt, t);
}
}
Run Code Online (Sandbox Code Playgroud)
是int t
类型的唯一“ID”,也是int xt
的实际类型的 ID x
。您可以看到if (xt != t || ...)
,Check_Type
检查类型等效性也是如此,而不是 is-a 关系。
Ruby 检查包含的模块是否实际上是一个模块而不是一个类。
归档时间: |
|
查看次数: |
191 次 |
最近记录: |