switch (TYPE(obj)) {
case T_FIXNUM:
/* process Fixnum */
break;
case T_STRING:
/* process String */
break;
case T_ARRAY:
/* process Array */
break;
default:
/* raise exception */
rb_raise(rb_eTypeError, "not valid value");
break;
}
static inline int
rb_type(VALUE obj)
{
if (IMMEDIATE_P(obj)) {
if (FIXNUM_P(obj)) return T_FIXNUM;
if (obj == Qtrue) return T_TRUE;
if (SYMBOL_P(obj)) return T_SYMBOL;
if (obj == Qundef) return T_UNDEF;
}
else if (!RTEST(obj)) {
if (obj == Qnil) return T_NIL;
if (obj == Qfalse) return T_FALSE;
}
return BUILTIN_TYPE(obj);
}
typedef unsigned long VALUE;
RHASH(h)->hash_method
#define RHASH(obj) (R_CAST(RHash)(obj))
#define R_CAST(st) (struct st*)
来看到RHASH的实现的.
上面是以一个Hash对象的操作为例,讲解R uby对象的存在方式(VALUE指针),以及习惯的操作方法(R_CAST转换).不过刚才也提到过Fixnum不是指针,为啥?如果一个VALUE的类型你能确定是Fixnum的话,就不需要去通过*取值了,我们可以直接拿到Fixnum的指,因为VALUE这个unsign long已经足够大了,它的长度足够存储一个Fixnum,所以Fixnum是以值而不是指针的形式存在的.
这也就说道Ruby中哪些类型是传值的,哪些类型是传址的.如果死记硬背那些教条,我估计肯定没有自己去发现Ruby的底层实现给你的印象更深刻.
下面这几个类型也很重要,尤其是True和False.
RUBY_Qfalse = 0,
RUBY_Qtrue = 2,
RUBY_Qnil = 4,
RUBY_Qundef = 6,
#define RTEST(v) (((VALUE)(v) & ~Qnil) != 0)
这个宏是用作判断一个VALUE对象是否为True或者为False和Nil的,这个判断就用到了上面的几个值的特点,为了让Ansi C的 if表达式在False和Nil的时候都走失败的分支,而只有True的时候走成功的分支.至于怎么实现,请用位运算计算一下,看看是不是取值设计的巧妙.
#define Qfalse ((VALUE)RUBY_Qfalse)
#define Qtrue ((VALUE)RUBY_Qtrue)
#define Qnil ((VALUE)RUBY_Qnil)
#define Qundef ((VALUE)RUBY_Qundef) /* undefined value for placeholder */
/**********************************************************************
main.c -
$Author: akr $
created at: Fri Aug 19 13:19:58 JST 1994
Copyright (C) 1993-2007 Yukihiro Matsumoto
**********************************************************************/
#undef RUBY_EXPORT
#include "ruby.h"
#include "debug.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
RUBY_GLOBAL_SETUP
int
main(int argc, char **argv)
{
#ifdef RUBY_DEBUG_ENV
ruby_set_debug_option(getenv("RUBY_DEBUG"));
#endif
#ifdef HAVE_LOCALE_H
setlocale(LC_CTYPE, "");
#endif
ruby_sysinit(&argc, &argv);
{
RUBY_INIT_STACK;
ruby_init();
return ruby_run_node(ruby_options(argc, argv));
}
}
#define CALL(n) {void Init_##n(void); Init_##n();}
void
rb_call_inits(void)
{
CALL(RandomSeed);
CALL(sym);
CALL(var_tables);
CALL(Object);
CALL(top_self);
CALL(Encoding);
CALL(Comparable);
CALL(Enumerable);
CALL(String);
/*..........*/
}