Ruby: явное определение области действия для определения класса - PullRequest
19 голосов
/ 07 января 2011

отказ от ответственности: код взят из 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, и я понимаю, почему - искать в лексическом пространстве константу до наследования heirarchy.

Тогда этот класс определен:

class MyAnimals::Oyster < Animal
  def legs_in_oyster
    LEGS
  end
end

В учебнике говорится, что теперь вызов MyAnimals::Oyster.new.legs_in_oyster приводит к 4, и я не могу понять это.Мне кажется, что Oyster - это вложенный класс в MyAnimals, и поэтому я ожидал, что он будет вести себя так же, как и класс Birds, описанный выше.Мне не хватает какой-то ключевой информации о том, что означает объявление класса Oyster с явным определением объема.

Может кто-нибудь объяснить мне это?Я нашел сотни учебников по рубиновому классу через Google, но ни один из них не разрешил эту ситуацию.

Заранее спасибо ...

Ответы [ 2 ]

22 голосов
/ 07 января 2011

Я думаю этот пример объясняет это лучше всего.Ruby ищет определение константы в следующем порядке:

  1. Включающая область действия
  2. Любые внешние области действия (повторяются до достижения верхнего уровня) Любые внешние области действия (вверхк, но не включая верхний уровень
  3. Включенные модули
  4. Суперкласс (ы)
  5. Верхний уровень
  6. Объект
  7. Kernel

EDIT

Благодаря 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
5 голосов
/ 07 января 2011

Если вы определите Oyster INSIDE для определения класса MyAnimals, тогда вы получите ответ, что leg_in_oyster равен 2.

Если вы определяете Устрицу отдельно, то есть определяете ее после того, как 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, будет сначала искать LEGS внутри MyAnimals.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...