Blog

Blog

PHODAL

ruby三日游之后(一)——Ruby对象的一次探索

来自Ruby世界似乎是这样说的,“Ruby内一切都是对象”。

有趣的一切都是对象,那么一切也就没有不再是对象了?

> "面向对象的设计方法是在结构化编程对控制流程实现了结构化后,又加上了对数据的结构化。"——《松本行弘的程序世界》

这里引用自《Ruby Hacking Guide》的对象一章的说法,对象存在的必要条件

  • 能够区分自身与其它(拥有标识)
  • 能够响应请求(方法)
  • 保持内部状态(实例变量)

Ruby 中的类层次结构

然后我们再看看一个有意思的结果:

    irb(main):022:0> Object.class
    => Class
    irb(main):023:0> Object.superclass
    => BasicObject
    irb(main):024:0> BasicObject.superclass
    => nil
    irb(main):025:0> 
这里使用的是1.9.3版本的ruby,于是这是Ruby的类层次结构,至于为什么是这样的,不凡看看下面的这些代码。

void
Init_class_hierarchy(void)
{
    rb_cBasicObject = boot_defclass("BasicObject", 0);
    rb_cObject = boot_defclass("Object", rb_cBasicObject);
    rb_cModule = boot_defclass("Module", rb_cObject);
    rb_cClass =  boot_defclass("Class",  rb_cModule);

    rb_const_set(rb_cObject, rb_intern("BasicObject"), rb_cBasicObject);
    RBASIC_SET_CLASS(rb_cClass, rb_cClass);
    RBASIC_SET_CLASS(rb_cModule, rb_cClass);
    RBASIC_SET_CLASS(rb_cObject, rb_cClass);
    RBASIC_SET_CLASS(rb_cBasicObject, rb_cClass);
}

这是用于初化化类层次的代码,也就是hierarchy的意思,层次,层次结构。

至于,boot_defclass那么就看看下面的

static VALUE
boot_defclass(const char *name, VALUE super)
{
    VALUE obj = rb_class_boot(super);
    ID id = rb_intern(name);

    rb_name_class(obj, id);
    rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
    return obj;
}

如果这里还有什么令人不明白的地方,那么可能就是VALUE了。 原文是这么长:


    #if defined HAVE_UINTPTR_T && 0
    typedef uintptr_t VALUE;
    typedef uintptr_t ID;
    # define SIGNED_VALUE intptr_t
    # define SIZEOF_VALUE SIZEOF_UINTPTR_T
    # undef PRI_VALUE_PREFIX
    #elif SIZEOF_LONG == SIZEOF_VOIDP
    typedef unsigned long VALUE;
    typedef unsigned long ID;
    # define SIGNED_VALUE long
    # define SIZEOF_VALUE SIZEOF_LONG
    # define PRI_VALUE_PREFIX "l"
    #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
    typedef unsigned LONG_LONG VALUE;
    typedef unsigned LONG_LONG ID;
    # define SIGNED_VALUE LONG_LONG
    # define LONG_LONG_VALUE 1
    # define SIZEOF_VALUE SIZEOF_LONG_LONG
    # define PRI_VALUE_PREFIX PRI_LL_PREFIX
    #else
    # error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
    #endif
那么,简化一下为和前几个版本一致的,那么就是

typedef unsigned long VALUE;

原本的模型应该是这样的

Ruby的对象变的

让我们再简单看一看一个示例


    irb(main):025:0> 1.class
    => Fixnum
    irb(main):026:0> Fixnum.class
    => Class
    irb(main):027:0> Fixnum.superclass
    => Integer
    irb(main):028:0> Fixnum.superclass.superclass
    => Numeric
    irb(main):029:0> Fixnum.superclass.superclass.superclass
    => Object
    irb(main):030:0> Fixnum.superclass.superclass.superclass.superclass
    => BasicObject
    irb(main):031:0> 
好吧,我觉得引用RHG中的图来说明可能会更简单一点,只是这张图只能做一时只用(转载保留

因为这些都已经改变了 原先的对象只有这些

#define R_CAST(st)   (struct st*)
#define RBASIC(obj)  (R_CAST(RBasic)(obj))
#define ROBJECT(obj) (R_CAST(RObject)(obj))
#define RCLASS(obj)  (R_CAST(RClass)(obj))
#define RMODULE(obj) RCLASS(obj)
#define RFLOAT(obj)  (R_CAST(RFloat)(obj))
#define RSTRING(obj) (R_CAST(RString)(obj))
#define RREGEXP(obj) (R_CAST(RRegexp)(obj))
#define RARRAY(obj)  (R_CAST(RArray)(obj))
#define RHASH(obj)   (R_CAST(RHash)(obj))
#define RDATA(obj)   (R_CAST(RData)(obj))
#define RSTRUCT(obj) (R_CAST(RStruct)(obj))
#define RBIGNUM(obj) (R_CAST(RBignum)(obj))
#define RFILE(obj)   (R_CAST(RFile)(obj))

可是现在呢?

#define R_CAST(st)   (struct st*)
#define RBASIC(obj)  (R_CAST(RBasic)(obj))
#define ROBJECT(obj) (R_CAST(RObject)(obj))
#define RCLASS(obj)  (R_CAST(RClass)(obj))
#define RMODULE(obj) RCLASS(obj)
#define RFLOAT(obj)  (R_CAST(RFloat)(obj))
#define RSTRING(obj) (R_CAST(RString)(obj))
#define RREGEXP(obj) (R_CAST(RRegexp)(obj))
#define RARRAY(obj)  (R_CAST(RArray)(obj))
#define RHASH(obj)   (R_CAST(RHash)(obj))
#define RDATA(obj)   (R_CAST(RData)(obj))
#define RTYPEDDATA(obj)   (R_CAST(RTypedData)(obj))
#define RSTRUCT(obj) (R_CAST(RStruct)(obj))
#define RBIGNUM(obj) (R_CAST(RBignum)(obj))
#define RFILE(obj)   (R_CAST(RFile)(obj))
#define RRATIONAL(obj) (R_CAST(RRational)(obj))
#define RCOMPLEX(obj) (R_CAST(RComplex)(obj))

比之前多了TYPEDATA,RATIONAL,COMPLEX三个对象

Ruby 不变的对象

让我们看看结构化的那部分

struct RBasic {
    VALUE flags;
    const VALUE klass;
}

以及Object

struct RObject {
    struct RBasic basic;
    union {
    struct {
        long numiv;
        VALUE *ivptr;
            struct st_table *iv_index_tbl; /* shortcut for RCLASS_IV_INDEX_TBL(rb_obj_class(obj)) */
    } heap;
    VALUE ary[ROBJECT_EMBED_LEN_MAX];
    } as;
};

还有Rstring

struct RString {
    struct RBasic basic;
    union {
    struct {
        long len;
        char *ptr;
        union {
        long capa;
        VALUE shared;
        } aux;
    } heap;
    char ary[RSTRING_EMBED_LEN_MAX + 1];
    } as;
};

于是让我们回到

对象存在的必要条件

  • 能够区分自身与其它(拥有标识)
  • 能够响应请求(方法)
  • 保持内部状态(实例变量)

    struct RBasic { VALUE flags; const VALUE klass; }

这两部分。

  • flags是个多目的的标记,大多用以记录结构体的类型。
  • klass包含了这个对象归属的类。

最后,让我们看看Float是怎么说的

struct RFloat {
    struct RBasic basic;
    double float_value;
};

或许您还需要下面的文章:

关于我

Github: @phodal     微博:@phodal     知乎:@phodal    

微信公众号(Phodal)

围观我的Github Idea墙, 也许,你会遇到心仪的项目

QQ技术交流群: 321689806
comment

Feeds

RSS / Atom

最近文章

关于作者

Phodal Huang

Engineer, Consultant, Writer, Designer

ThoughtWorks 技术专家

工程师 / 咨询师 / 作家 / 设计学徒

开源深度爱好者

出版有《前端架构:从入门到微前端》、《自己动手设计物联网》、《全栈应用开发:精益实践》

联系我: h@phodal.com

微信公众号: 最新技术分享

标签