• 2006-09-13

    管窥Ruby——对象基础

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-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指向超类。这样,只要我们知道对象就可以找到它的类信息了,一个庞大的系统就此运转起来。

    分享到:

    历史上的今天:

    引用地址:

    评论

  • 写得好
  • VALUE即做指针,又作整数用。大多数情况下是指针,在代表Fixnum之类的时候就是unsigned long(有一个bit来标示区别).在dynamic language里这是很常见的一种表示法,尽管很多人并不喜欢。在java之类的语言里无法将指针和整数相互转换,于是只好都用Object,这样使数字运算的性能更低。但也带来一点点附加的好处.
    回复yawl说:
    此外,在Hash表中,键值统一用数值表示,这样的定义让VALUE可以直接作为键值,把Hash表的处理统一起来。 在Python中,整数当作一个单独的对象处理,而不像Ruby这样,把值直接放到了VALUE中。 在Java中,指针(也就是引用)只保留“指向”的语义,而舍弃了其“地址”的含义,因此无法与整数之间进行转换。
    2006-09-14 08:25:22