六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 1003|回复: 0

[RubyHackingGuide]统一处理对象之VALUE

[复制链接]

升级  60%

8

主题

8

主题

8

主题

童生

Rank: 1

积分
30
 楼主| 发表于 2013-2-5 02:45:00 | 显示全部楼层 |阅读模式
VALUE是Ruby的C实现中用来"指向/引用/代表"所有Ruby对象的"指针"的统一的类型

通过统一类型,可以获得类似"多态"的好处,ruby实现起来就更为简洁(代码方面).
然后, 同样是出于实现的考虑(性能方面), VALUE并不全是指针:
   1. 小的整数
   2. 符号
   3. true
   4. false
   5. nil
   6. Qundef
以上六位就是所谓的"内嵌对象"(VALUE并不是内存地址,其代表的对象是内嵌在VALUE的数值中).

小整数的内嵌规则是:
#define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG))  #define FIXNUM_FLAG 0x01
数值乘以2再加1(奇数).

符号的内嵌规则是:
#define SYMBOL_FLAG 0x0e  #define ID2SYM(x) ((VALUE)(((long)(x))<<8|SYMBOL_FLAG))  
数值乘以256再加14(不能被4整除的偶数)
看到这里,大家可能会疑惑,小整数的数值是本身,但符号(Symbol)的数值又是什么呢?
简单来说,每个ruby进程中维护了一个字符串和数值一一对应的hash表,
因此就可以使用数值来代表(Identify)字符串所表示的"名字", 减少了内存和字符串比较的开销.
static NODE*  search_method(klass, id, origin)        VALUE klass, *origin;        ID id;  {        NODE *body;          if (!klass) return 0;        while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) {            klass = RCLASS(klass)->super;            if (!klass) return 0;        }          if (origin) *origin = klass;        return body;  }  
例如这个search_method就是在klass类中搜索名称的ID为id的方法, 并将方法的"出处"(定义方法的类)保存在orgin中.
Ruby为"数值"的"特殊使用"(用做'名字'的ID)单独创建了一个类型:符号(Symbol).

3-6的内嵌规则是:
#define Qfalse 0        /* Ruby's false */  #define Qtrue  2        /* Ruby's true */  #define Qnil   4        /* Ruby's nil */ #define Qundef 6        /* undefined value for placeholder */  

除了内嵌对象外, VALUE的值便是Ruby对象对应的C结构体的内存地址.
C结构体的内存通常不是从第一个块(0-?)开始分配的,因此不会和Qfalse,Qnil冲突.
且所有Ruby对象的C结构体的共同特征是,其内存地址一定是4的倍数(还记得C中Struct对齐么?).
因此,仅凭VALUE的数值就可以区分它是小整数,符号,Q值,还是内存地址(有例外!).

switch (TYPE(obj)) {        /* (A) */          case T_OBJECT:          case T_CLASS:          case T_MODULE:            if (ROBJECT(obj)->iv_tbl &&                    st_lookup(ROBJECT(obj)->iv_tbl, id, &val))                return val;            break;        /* (B) */          default:            if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))                return generic_ivar_get(obj, id);            break;        }
看到代码中的TYPE宏么, 就是根据VALUE的数值返回obj可能指向的结构体的类型.
例如,一个RString类型的结构体实例的TYPE就是T_STRING. 那么TYPE(2)会返回T_FIXNUM么?
错! 应返回T_TRUE?(如果有...), 而TYPE(3)则返回T_FIXNUM.

TYPE宏可以区分内嵌对象和对象,那么,它是如何区分不同的对象的呢?此时,VALUE的值都是内存地址, 不同的是它所指向的结构体.正如你想的那样, TYPE宏在运行时区分结构体类型的能力正是来源于结构体本身,换句话说,结构体存储了自身的类型信息.关于这些结构体,详见 Ruby的对象类.
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表