免责声明:代码取自ruby koans
这是对类中常量范围的讨论。以下是几个班级的定义:
class Animal
LEGS = 4
def legs_in_animal
LEGS
end
end
class MyAnimals
LEGS = 2
class Bird < Animal
def legs_in_bird
LEGS
end
end
end
此时执行MyAnimals::Bird.new.legs_in_bird
导致2并且我理解为什么 - 在继承层次之前搜索常量的词法空间。
然后定义了这个类:
class MyAnimals::Oyster < Animal
def legs_in_oyster
LEGS
end
end
教程说现在调用MyAnimals::Oyster.new.legs_in_oyster
导致4,我无法弄明白。在我看来,Oyster是MyAnimals中的嵌套类,因此我希望它的行为与Birds类在上面的行为相同。我遗漏了一些关于用明确的范围界定声明类Oyster的关键信息。
任何人都可以向我解释这个吗?我已经通过谷歌发现了数百个ruby课程教程,但没有一个能解决这种情况。
提前谢谢你......
答案 0 :(得分:22)
我认为this example解释得最好。 Ruby按此顺序搜索常量定义:
修改
感谢Mark Amery指出此错误。只有在没有封闭范围和/或超类的情况下才能达到顶级。链接的例子实际上清楚地表明了这一点,遗憾的是我读错了。
这种情况的一个例子:
FOO = 'I pity the foo!'
module One
FOO = 'one'
class Two
FOO = 'two'
def self.foo
FOO
end
end
class Three < Two
def self.foo
FOO
end
end
end
class Four
class Five < Four
def self.foo
FOO
end
end
end
describe FOO do
it "depends where it is defined" do
expect(FOO).to eq 'I pity the foo!' # top-level
expect(One::FOO).to eq 'one' # module
expect(One::Two.foo).to eq 'two' # class
expect(One::Three.foo).to eq 'one' # outer scope (One) comes before superclass
expect(Four::Five.foo).to eq 'I pity the foo!' # top-level
end
end
答案 1 :(得分:5)
如果你定义Oyster INSIDE MyAnimals类定义,那么你得到leg_in_oyster为2的答案。
如果您单独定义Oyster - 也就是说,在LEGS = 2超出范围后定义它,则会得到4的响应。
这告诉我,嵌套类的行为与命名空间的行为不同,可能更像是一个闭包。
--- --- EDIT
irb(main):076:0> class MyAnimals::RunningRoach < Animal; def using_legs; LEGS; end; end
=> nil
irb(main):077:0> MyAnimals::RunningRoach.new.kind_of?(MyAnimals)
=> false
irb(main):078:0> MyAnimals::RunningRoach.new.kind_of?(Animal)
=> true
irb(main):081:0> class MyAnimals::Mantis < MyAnimals; def killing_legs; LEGS; end; end
=> nil
irb(main):082:0> MyAnimals::Mantis.new.kind_of?(Animal)
=> false
irb(main):083:0> MyAnimals::Mantis.new.kind_of?(MyAnimals)
=> true
irb(main):084:0> MyAnimals::Mantis.new.killing_legs
=> 2
irb(main):085:0> MyAnimals::RunningRoach.new.using_legs
=> 4
根据“Ruby编程语言”,常量会在首先使用它们的地方的词法范围中查找,然后在继承层次结构中查找。那么继承Animal的词汇范围是什么?动物本身吧? MyAnimals类重新定义了LEGS,因此任何使用LEGS并且在 MyAnimals内定义的东西都将首先在MyAnimals中查找LEGS。