-
2006-09-13
管窥Ruby——对象基础
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://dreamhead.blogbus.com/logs/3299713.html
从C/C++或Java这种静态类型语言起步的人,初涉Ruby之类动态类型语言的时候,感觉最明显的差异莫过于无处着力的类型了,每每编写程序,总会习惯性的加上类型的声明,这虽不是什么大不了的事情,但总要有个适应的过程。
形,需要有神对应,代码中没有体现类型,那么在实现中,就要把所有的对象纳入同一个体系之中。Ruby的基本实现以C完成,在C中不可能再去除类型,因此总要有个类型作为基础,就像Java中所有类的基类都是Object一样。在Ruby的实现中,随处可见的是VALUE类型,它就是我们要找的根。熟悉C的人都知道,要想实现这种可以代表一切的东西,最常用的类型就是void*。稍微有些出乎意料,下面就是VALUE的定义:
typedef unsigned long VALUE;
(ruby.h)对于很多熟悉C编程的人而言,指针就是一个整数,一个内存地址,所以,unsigned long与void*之间没有本质的差别,事实上,在Ruby的代码中,VALUE确实经常被当作普通的指针使用。当然,这里存在一个问题,只有unsigned long和void*大小相同的时候,我们才能安心使用。严格说来,unsigned long大点也没有关系。至少在现在的大多数机器上,这种假设可以完全得到满足,所以,Ruby舒舒服服的运行着。所以,查看Ruby代码的时候,我们完全可以把VALUE视为一个普通的指针。
有合自然要有分,纳入统一的体系没有问题,但在做实际处理的时候,我们还是要知道一些关于类的信息:可能是具体的类型,可能是需要执行的方法。如果需要了解具体的类型,直接转型是最为便捷的选择,对于内建的类型,Ruby提供了一些宏,用来简化代码的编写,比如:
VALUE str = ... ;
RSTRING(str)->len;这里就是把str转型为字符串进行处理。对了,我们还没看到字符串的结构体定义,那么下面就来看一下,顺便多看几个内建类型对应的C结构:
struct RObject {
struct RBasic basic;
struct st_table *iv_tbl;
};struct RString {
struct RBasic basic;
long len;
char *ptr;
union {
long capa;
VALUE shared;
} aux;
};struct RArray {
struct RBasic basic;
long len;
union {
long capa;
VALUE shared;
} aux;
VALUE *ptr;
};
(ruby.h)再来看一下转型是如何做:
#define R_CAST(st) (struct st*)#define RSTRING(obj) (R_CAST(RString)(obj))
(ruby.h)这几段代码合在一起印证了前面提到的把VALUE当指针的说法。实际上,在Ruby中,真正这么用的时候并不多,毕竟在C层次上的类是少数,多数的还是在Ruby层次上。所以,更多的时候,我们要知道类相关的信息,早在Java的时候,我们就知道了所谓元对象的存在,那我们不妨来看一下在Ruby中这是如何实现的。之所以要多列几个类,是为了发现共同点,抛开类的具体内容,我们发现在这几个类定义都是以struct RBasic开头,看一下它的定义:
struct RBasic {
unsigned long flags;
VALUE klass;
};
(ruby.h)flags的作用自然是记录类的一些信息,让我们暂且略过,把目光放在klass上,没错,名字已经告诉我们,它就是要找的类对象。它对应C结构是
struct RClass,其定义如下:struct RClass {
struct RBasic basic;
struct st_table *iv_tbl;
struct st_table *m_tbl;
VALUE super;
};
(ruby.h)一目了然,basic是所有类共有的定义,指向它的类,这里不必深究,那是另外的故事了。iv_tbl和m_tbl分别存放变量和方法,super指向超类。这样,只要我们知道对象就可以找到它的类信息了,一个庞大的系统就此运转起来。
引用地址:








评论