Подтвердить что ты не робот

Ruby: явное определение определения класса

отказ от ответственности: код, взятый из 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 с явным средством определения области видимости.

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

благодарим вас заранее...

4b9b3361

Ответ 1

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

  • Прилагаемый объем
  • Любые внешние области (повторяются до достижения верхнего уровня) Любые внешние области (до, но не включая верхний уровень
  • Включенные модули
  • суперкласса (ов)
  • Верхний уровень
  • Объект
  • Kernel

ИЗМЕНИТЬ

Благодаря 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

Ответ 2

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