Я читал эту книгу о Ruby, а затем еще один пример, который я не очень хорошо понял:

CONST = "outer"
module Mod
    CONST = 1
    def Mod.method1
        # module method
        CONST + 1
    end
end
module Mod::Inner
    def (Mod::Inner).method2
        CONST + " scope"
    end
end
Mod::CONST  # => 1
Mod.method1 # => 2
Mod::Inner::method2 # => "outer scope"

Не могли бы вы объяснить мне это (подробное объяснение), чтобы я мог полностью понять, как работает область видимости в Ruby. Спасибо.

1
devio 31 Дек 2013 в 01:48

2 ответа

Лучший ответ

Константы в Ruby (идентификаторы, начинающиеся с заглавной буквы) доступны на основе лексической области видимости, в которой они определены / доступны.

В method1 CONST в области Mod имеет приоритет над самым внешним CONST. В method2 CONST в области Mod не виден лексически, поэтому осуществляется доступ к самому внешнему CONST.

Что касается самих определений методов, когда имя уточняется с помощью предшествующей константы модуля (например, Mod или Mod::Inner), метод определяется как "метод модуля", а не как метод экземпляра self.class (по умолчанию).

Имена в иерархии модуля / метода разделяются знаком :: или, в качестве альтернативы, в случае разделителя между модулем и методом модуля, ..

Обновление : обратите внимание, что причина, по которой константы Mod не видны для method2, заключается в том, что Mod не был отдельно "открыт". Определение пропущено непосредственно к Mod::Inner. Если код был изменен на:

module Mod
  module Inner
    def (Mod::Inner).method2
      ...

Тогда константы Mod будут доступны для method2 и будут иметь приоритет над любыми во внешней области видимости.

2
Peter Alfvin 30 Дек 2013 в 22:19

Вы можете найти хорошее объяснение поиска в Ruby Constant здесь

Я бы поделился фрагментами кода с некоторыми пояснениями:

CONST = "outer"
module Mod
  CONST = 1
  def Mod.method1
    # module method
    Module.nesting # => [Mod]
    CONST + 1
  end
end
module Mod::Inner
  def (Mod::Inner).method2
    Module.nesting # => [Mod::Inner]
    CONST + " scope"
  end
end


Mod::CONST  # => 1
Mod.method1 # => 2
Mod::Inner::method2 # => "outer scope"

Взгляните на оценку Module.nesting выше (Mod::Inner).method2 ищет в Mod::Inner, как указано во вложении для CONST, которое не находит до того, как вызовет основной объект для CONST

В приведенном ниже примере вы увидите, что Mod::Inner.method2 вызывает Mod :: Inner, а затем Mod для поиска найденного CONST, поэтому нет необходимости вызывать CONST в объекте

module Mod
  CONST = 1
  def Mod.method1
    Module.nesting # => [Mod]
    CONST + 1
  end

  module Inner
    def (Mod::Inner).method2
      Module.nesting # => [Mod::Inner, Mod]
      CONST.to_s + " scope"
    end
  end
end


Mod::CONST  # => 1
Mod.method1 # => 2
Object::CONST # => "outer"
Mod::Inner::method2 # => "1 scope"

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

2
bjhaid 30 Дек 2013 в 22:54