我正在研究 Pickaxe 1.9,并且对 instance/class_eval 块中的常量查找感到有点困惑。我用的是1.9.2。
Ruby 似乎以与方法查找相同的方式处理 *_eval 块中的常量查找:
- 在receiver.singleton_class(加上mixins)中查找定义;
- 然后在receiver.singleton_class.superclass(加上mixins)中;
- 然后继续沿着特征链向上直到你到达
#<Class:BasicObject>
;
- 其超类是 Class;
- 然后沿着祖先链的其余部分(包括
Object
,它存储您在顶层定义的所有常量),一路检查 mixins
它是否正确?镐的讨论有点简洁。
一些例子:
class Foo
CONST = 'Foo::CONST'
class << self
CONST = 'EigenFoo::CONST'
end
end
Foo.instance_eval { CONST } # => 'EigenFoo::CONST'
Foo.class_eval { CONST } # => 'EigenFoo::CONST', not 'Foo::CONST'!
Foo.new.instance_eval { CONST } # => 'Foo::CONST'
在 class_eval 示例中,Foo-the-class 并不是 Foo-the-object 的祖先链上的停止点!
还有一个 mixins 的例子:
module M
CONST = "M::CONST"
end
module N
CONST = "N::CONST"
end
class A
include M
extend N
end
A.instance_eval { CONST } # => "N::CONST", because N is mixed into A's eigenclass
A.class_eval { CONST } # => "N::CONST", ditto
A.new.instance_eval { CONST } # => "M::CONST", because A.new.class, A, mixes in M
在 1.9.2 中,常量查找发生了变化again相当于 1.8.7 行为。
class A
class B
class C
end
end
end
A.class_eval { B } # => NameError
A.instance_eval { B } # => NameError
A.new.instance_eval { B } # => A::B
基本上,常量是准词法范围的。这在 1.9.x 和 1.8.x 分支之间曾经是不同的,这使得库交叉兼容性变得很痛苦,所以他们把它改回来了。
Yehuda Katz(成功)呼吁恢复 1.8 行为
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)