我想知道nil
单例对象在Ruby源代码中的实例化位置。
有什么想法吗?
答案 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中的快乐谎言。它甚至根本不是一个真实的物体;这只是一个特殊的魔术数字。 true
和false
也在同一枚举中定义。实际上,我们可以检查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
false
,true
和nil
的标识符等于*等于我们在枚举中找到的值,因此看起来像这样。
值得注意的是,虽然 nil 本身在VM中是一个快乐的谎言,但是nil
上的方法当然是非常真实的。 NilClass
在InitVM_Object
中定义,其方法也是如此。但是nil
本身从未被初始化。
*从技术上讲,您的价值观可能会有所不同。此处列出的枚举值受#if USE_FLONUM
块的保护,该块根据系统上各种常量的大小而设置或未设置。您可以在ruby.h
中查看该标志的条件以及其他几个类似的条件。
答案 2 :(得分:1)
即,我们有以下几行:
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
的无数引用