“ NilClass”单例实例在哪里实例化?

时间:2018-07-17 15:12:37

标签: ruby

我想知道nil单例对象在Ruby源代码中的实例化位置。

有什么想法吗?

3 个答案:

答案 0 :(得分:3)

至少在MRI中,nil(以及true和false)是在“ C”解释器代码中静态创建的特殊常量。

因此,它们不是正常意义上创建的。相反,其对象ID是一种nil标记,可以根据需要在代码中进行测试。虽然有点混乱,但这会加快速度。

/* special constants - i.e. non-zero and non-fixnum constants */
405 enum ruby_special_consts {
406 #if USE_FLONUM
407     RUBY_Qfalse = 0x00,         /* ...0000 0000 */
408     RUBY_Qtrue  = 0x14,         /* ...0001 0100 */
409     RUBY_Qnil   = 0x08,         /* ...0000 1000 */
410     RUBY_Qundef = 0x34,         /* ...0011 0100 */
411 
412     RUBY_IMMEDIATE_MASK = 0x07,
413     RUBY_FIXNUM_FLAG    = 0x01, /* ...xxxx xxx1 */
414     RUBY_FLONUM_MASK    = 0x03,
415     RUBY_FLONUM_FLAG    = 0x02, /* ...xxxx xx10 */
416     RUBY_SYMBOL_FLAG    = 0x0c, /* ...0000 1100 */
417 #else
418     RUBY_Qfalse = 0,            /* ...0000 0000 */
419     RUBY_Qtrue  = 2,            /* ...0000 0010 */
420     RUBY_Qnil   = 4,            /* ...0000 0100 */
421     RUBY_Qundef = 6,            /* ...0000 0110 */
422 
423     RUBY_IMMEDIATE_MASK = 0x03,
424     RUBY_FIXNUM_FLAG    = 0x01, /* ...xxxx xxx1 */
425     RUBY_FLONUM_MASK    = 0x00, /* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */
426     RUBY_FLONUM_FLAG    = 0x02,
427     RUBY_SYMBOL_FLAG    = 0x0e, /* ...0000 1110 */
428 #endif
429     RUBY_SPECIAL_SHIFT  = 8
430 };

答案 1 :(得分:2)

如果我们看一下Github上的Ruby源代码,我们可以看到大多数内核功能都是在InitVM_Object中初始化的。但是,nil显然不存在,其存在的唯一线索是

/*
 * An obsolete alias of +nil+
 */
rb_define_global_const("NIL", Qnil);

,诚然,我实际上并不知道NIL甚至在Ruby中也可以工作,但这不重要。现在我们知道,在Ruby的C代码中,Qnil是我们的“ nil”对象。事实证明,我们可以将其追溯到ruby.h中的 来源。 Qnil不是变量;这是#define的实用指令。

#define Qnil RUBY_Qnil
另一方面,

RUBY_Qnil被定义为枚举常量。

enum ruby_special_consts {
    RUBY_Qfalse = 0x00,     /* ...0000 0000 */
    RUBY_Qtrue  = 0x14,     /* ...0001 0100 */
    RUBY_Qnil = 0x08,       /* ...0000 1000 */
    ...
}

所以nil看起来像是Ruby中的快乐谎言。它甚至根本不是一个真实的物体;这只是一个特殊的魔术数字。 truefalse也在同一枚举中定义。实际上,我们可以检查Ruby本身是否正确。

irb(main):009:0> false.object_id
=> 0
irb(main):010:0> true.object_id
=> 20
irb(main):011:0> nil.object_id
=> 8

falsetruenil的标识符等于*等于我们在枚举中找到的值,因此看起来像这样。

值得注意的是,虽然 nil 本身在VM中是一个快乐的谎言,但是nil上的方法当然是非常真实的。 NilClassInitVM_Object中定义,其方法也是如此。但是nil本身从未被初始化

*从技术上讲,您的价值观可能会有所不同。此处列出的枚举值受#if USE_FLONUM块的保护,该块根据系统上各种常量的大小而设置或未设置。您可以在ruby.h中查看该标志的条件以及其他几个类似的条件。

答案 2 :(得分:1)

It's defined here

即,我们有以下几行:

RUBY_Qnil   = 0x08

#define RUBY_Qnil   ((VALUE)RUBY_Qnil)
#define Qnil  RUBY_Qnil

这就是nil.object_id == 8的原因。

然后定义

NilClass及其方法here

rb_cNilClass = rb_define_class("NilClass", rb_cObject);
rb_define_method(rb_cNilClass, "to_i", nil_to_i, 0);
rb_define_method(rb_cNilClass, "to_f", nil_to_f, 0);
rb_define_method(rb_cNilClass, "to_s", nil_to_s, 0);
rb_define_method(rb_cNilClass, "to_a", nil_to_a, 0);
rb_define_method(rb_cNilClass, "to_h", nil_to_h, 0);
rb_define_method(rb_cNilClass, "inspect", nil_inspect, 0);
rb_define_method(rb_cNilClass, "&", false_and, 1);
rb_define_method(rb_cNilClass, "|", false_or, 1);
rb_define_method(rb_cNilClass, "^", false_xor, 1);
rb_define_method(rb_cNilClass, "===", rb_equal, 1);

rb_define_method(rb_cNilClass, "nil?", rb_true, 0);
rb_undef_alloc_func(rb_cNilClass);
rb_undef_method(CLASS_OF(rb_cNilClass), "new");

在整个MRI源代码中,您将发现对Qnil的无数引用