阅读Ruby的源代码,我可以解释的是:
instance_eval正在执行这个:
return specific_eval(argc, argv, klass, self)
依次运行:
if (rb_block_given_p()) {
if (argc > 0) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
}
return yield_under(klass, self, Qundef);
}
你可以看到他们通过Qundef
对于 VALUES 参数。
if (values == Qundef) {
return vm_yield_with_cref(th, 1, &self, cref);
}
在该特定代码行中,他们手动将 argc(参数计数)设置为 1,并将参数设置为“self”。稍后,准备块的代码将块的参数设置为这些参数,因此第一个参数 =“self”,其余参数为零。
设置块参数的代码正在执行以下操作:
arg0 = argv[0];
... bunch of code ...
else {
argv[0] = arg0;
}
for (i=argc; i<m; i++) {
argv[i] = Qnil;
}
导致:
1.9.3p194 :006 > instance_eval do |x, y, z, a, b, c, d| x.class end
=> Object
1.9.3p194 :008 > instance_eval do |x, y, z, a, b, c, d| y.class end
=> NilClass
为什么 ?我不知道,但代码似乎是故意的。很高兴向实施者提出问题,看看他们对此有何评论。
[Edit]
这可能是这样的,因为您传递给 instance_eval 的块可能会或可能不会为其制作(代码取决于将 self 设置为您想要块修改的类),相反,它们可能会假设您将向它们传递您希望它们作为参数进行修改的实例,这样它们也可以与 instance_eval 一起使用。
irb(main):001:0> blk = Proc.new do |x| x.class end
#<Proc:0x007fd2018447b8@(irb):1>
irb(main):002:0> blk.call
NilClass
irb(main):003:0> instance_eval &blk
Object
当然这只是一个理论,没有官方文档我只能猜测。