[RubyHackingGuide]统一处理对象之VALUE

VALUE是Ruby的C实现中用来"[i]指向/引用/代表[/i]"所有Ruby对象的"[i]指针[/i]"的统一的类型
[img]/upload/attachment/125399/d869125d-18c6-3620-9169-63bd2d788064.png[/img]
通过统一类型,可以获得类似"多态"的好处,ruby实现起来就更为简洁(代码方面).
然后, 同样是出于实现的考虑(性能方面), VALUE并不全是指针:
1. 小的整数
2. 符号
3. true
4. false
5. nil
6. Qundef
以上六位就是所谓的"内嵌对象"(VALUE并不是内存地址,其代表的对象是内嵌在VALUE的数值中).

[url=http://winteen.iteye.com/admin/blogs/426575][b]小整数[/b][/url]的内嵌规则是:
#define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG))  
#define FIXNUM_FLAG 0x01

数值乘以2再加1(奇数).

[b][url]符号[/url][/b]的内嵌规则是:
#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).

[b]3-6[/b]的内嵌规则是:
#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值,还是内存地址(有[url]例外[/url]!).

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的[url=http://winteen.iteye.com/admin/blogs/427213]对象类[/url].
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值