Ruby:对类定义的显式范围

jay*_*del 20 ruby class

免责声明:代码取自红宝石公案

这是对类中常量范围的讨论.这是几个类的定义:

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
Run Code Online (Sandbox Code Playgroud)

此时MyAnimals::Bird.new.legs_in_bird在2中做结果我理解为什么 - 在继承heirarchy之前搜索常量的词法空间.

然后定义这个类:

class MyAnimals::Oyster < Animal
  def legs_in_oyster
    LEGS
  end
end
Run Code Online (Sandbox Code Playgroud)

该教程说,现在调用MyAnimals::Oyster.new.legs_in_oyster4的结果,我无法弄明白.在我看来,Oyster是MyAnimals中的嵌套类,因此我希望它的行为与Birds类在上面的行为相同.我遗漏了一些关于用明确的范围方法声明类Oyster的关键信息.

任何人都可以向我解释这个吗?我已经通过Google找到了数百个红宝石课程教程,但没有一个能解决这个问题.

先感谢您...

zet*_*tic 23

我认为这个例子解释得最好.Ruby按此顺序搜索常量定义:

  1. 封闭范围
  2. 任何外部范围(重复到达顶级)任何外部范围(最多但不包括顶级
  3. 包含的模块
  4. 超(ES)
  5. 顶层
  6. 宾语
  7. 核心

编辑

感谢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
Run Code Online (Sandbox Code Playgroud)


phi*_*dad 5

如果你定义Oyster INSIDE MyAnimals类定义,那么你得到leg_in_oyster为2的答案.

如果单独定义Oyster - 也就是说,在LEGS = 2超出范围后定义它,则得到4的响应.

这告诉我,嵌套类的行为与命名空间的行为不同,可能更像是一个闭包.

- -编辑 - -

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
Run Code Online (Sandbox Code Playgroud)

根据"Ruby编程语言",常量在首先使用它们的地方的词法范围中查找,然后在继承层次结构中查找.那么继承Animal的词汇范围是什么?动物本身吧?MyAnimals类重新定义LEGS,因此任何使用LEGS并 MyAnimals中定义的东西都将首先在MyAnimals中查找LEGS.