Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是什么阻止我在Ruby中包含类?_Ruby_Class_Include - Fatal编程技术网

是什么阻止我在Ruby中包含类?

是什么阻止我在Ruby中包含类?,ruby,class,include,Ruby,Class,Include,我试图理解一些Ruby的内部结构: 试图包含类而不是模块,会导致类型错误:(这是出于设计) 我想知道“引擎盖下”的型式检验是如何工作的 由于类是模块,我假设Ruby检查参数是否是模块的实际实例: C.is_a?(Module) #=> true C.instance_of?(Module) #=> false 听起来很合理,不是吗 但是,当我定义自己的模块子类并创建该子类的实例时,它工作得很好: class Klass < Module end K = Kla

我试图理解一些Ruby的内部结构:

试图
包含类而不是模块,会导致
类型错误
:(这是出于设计)

我想知道“引擎盖下”的型式检验是如何工作的

由于类是模块,我假设Ruby检查参数是否是
模块的实际实例:

C.is_a?(Module)        #=> true
C.instance_of?(Module) #=> false
听起来很合理,不是吗

但是,当我定义自己的
模块
子类并创建该子类的实例时,它工作得很好:

class Klass < Module
end

K = Klass.new

Foo.include(K)
# no error
那么,签入
包含的类型实际上是做什么的呢

是否有一个隐藏属性允许Ruby区分模块和类


因为这是特定于实现的:我对YARV/MRI特别感兴趣。

正如@Stefan评论的那样,
Module\include
调用宏
检查类型(Module,T\u Module)
。你可以在一本书中找到这个

进一步挖掘源代码,您可以发现在头文件ruby.h中有一行

#define Check_Type(v,t) rb_check_type((VALUE)(v),(t))
因此,
Check\u Type
只是
rb\u Check\u Type
的一个方便的别名,您可以在error.c中找到
rb\u Check\u 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);   
    }
} 
int t
是一个类型的唯一“ID”,而
int xt
x
的实际类型的ID。您可以看到
if(xt!=t | | |…)
,因此
Check_Type
正在检查类型等价性,而不是is-a关系

TL;博士 Ruby检查所包含的模块是否实际上是一个模块而不是一个类。

我在这里回答我自己的问题


是否有一个隐藏属性允许Ruby区分模块和类

确实有。在内部,所有Ruby对象都以一个名为
RBasic
的结构开始:

struct RBasic{
价值标志;
常数值klass;
};
RBasic
中,我们有
标志
,这些标志包含类型信息:

module M ; end
class C ; end

Marshal.dump(M) #=> "\x04\bm\x06M"
Marshal.dump(C) #=> "\x04\bc\x06C"
Marshal.dump(4) #=> "\x04\bi\t"
#                          ^
#              m = module, c = class, i = integer
enum ruby\u值\u类型{
RUBY\u T\u NONE=0x00,
RUBY\u T\u对象=0x01,
RUBY\u T\u CLASS=0x02,
RUBY\u T\u模块=0x03,
RUBY\u T\u FLOAT=0x04,
RUBY\u T\u字符串=0x05,
// ...
RUBY\u T\u MASK=0x1f
};
这就是Ruby在进行类型检查时最终检查的内容:

#定义RB_内置类型(x)(int)(((struct RBasic*)(x))->标志和RUBY_T_掩码)
RB\u内置类型
也被
Marshal
用来转储类型信息:

module M ; end
class C ; end

Marshal.dump(M) #=> "\x04\bm\x06M"
Marshal.dump(C) #=> "\x04\bc\x06C"
Marshal.dump(4) #=> "\x04\bi\t"
#                          ^
#              m = module, c = class, i = integer
在Ruby中,我们可以通过以下方式检查内部类型:

现在,类型从
0x02
(类)更改为
0x03
(模块):

然后我们开始了:一个课程包含在另一个课程中


注意:我在这里摆弄Ruby的内部结构。不要在生产中使用这种技巧。您已收到警告。

可能它会直接检查这是否是
类的实例。
K.is_a?(Class)#=>false
C.is_a?(Class)#=>true
@MarekLipka在我看到的C源代码中
Check_Type(module,T_module)
,即显式检查T_模块,但没有像“not T T_Class”这样的反比
module M ; end
class C ; end

Marshal.dump(M) #=> "\x04\bm\x06M"
Marshal.dump(C) #=> "\x04\bc\x06C"
Marshal.dump(4) #=> "\x04\bi\t"
#                          ^
#              m = module, c = class, i = integer
require 'fiddle'

def type(obj)
  struct = Fiddle::Pointer.new(obj.object_id << 1)
  flags = struct[0]
  flags & 0x1f
end

module M ; end
class C ; end

type(M) #=> 3   (RUBY_T_MODULE = 0x03)
type(C) #=> 2   (RUBY_T_CLASS = 0x02)
class C
  def hello
    'hello from class'
  end
end

class Foo
end

Foo.include(C)
#=> TypeError: wrong argument type Class (expected Module)
require 'fiddle'

struct = Fiddle::Pointer.new(C.object_id << 1)
struct[0] = (struct[0] & ~0x1f) | 0x03

Foo.include(C)
# NoMethodError: undefined method `append_features' for C:Class
C.define_singleton_method(:append_features, Module.instance_method(:append_features))

Foo.include(C)
# no error!

Foo.ancestors
#=> [Foo, C, Object, BasicObject, Object, Kernel, BasicObject]

Foo.new.hello
#=> "hello from class"