Создание переменных модуля в Ruby

#ruby #module #class-variables

#ruby #модуль #переменные класса

Вопрос:

Есть ли какой-либо способ создать переменную в модуле в Ruby, которая вела бы себя аналогично переменной класса? Под этим я подразумеваю, что к нему можно было бы получить доступ без инициализации экземпляра модуля, но его можно изменить (в отличие от констант в модулях).

Ответ №1:

Ruby изначально поддерживает переменные класса в модулях, поэтому вы можете использовать переменные класса напрямую, а не какие-то прокси или псевдоклассовые переменные:

 module Site
  @@name = "StackOverflow"

  def self.setName(value)
    @@name = value
  end

  def self.name
    @@name
  end
end

Site.name            # => "StackOverflow"
Site.setName("Test")
Site.name            # => "Test"
  

Комментарии:

1. 1 На самом деле, я думал, что термин «переменная класса» вводит в заблуждение. Классы являются частными случаями модулей, а переменные класса могут быть определены в модулях. Они должны называться переменными модуля.

2. @sawa: Это несколько вводит в заблуждение, но это то, что использует сам Ruby: defined?(@@foo) => "class variable" .

3. Или их можно было бы назвать статическими полями. Кажется, это то, чем они являются.

4. @coreyward Привет, это моя ошибка. Зачем нужны две переменные класса ‘@@’? Разве это не считается запахом кода, особенно если класс расширен для использования переменных класса? Я тестировал это и понял, что могу получить тот же результат из одной @ переменной экземпляра. Есть ли конкретная причина для использования переменных класса? Спасибо за ответ.

5. почему разные вызовы в конце: T.get и T::get ?

Ответ №2:

Если вам не нужно вызывать его из экземпляра, вы можете просто использовать переменную экземпляра в теле модуля.

 module SomeModule
  module_function
  def param; @param end
  def param= v; @param = v end
end

SomeModule.param
# => nil
SomeModule.param = 1
SomeModule.param
# => 1
  

Тогда переменная экземпляра @param будет принадлежать модулю SomeModule , который является экземпляром Module класса.

Ответ №3:

вы можете установить переменную экземпляра класса в модуле.

 module MyModule
   class << self; attr_accessor :var; end
end

MyModule.var = 'this is saved at @var'

MyModule.var    
=> "this is saved at @var"
  

Комментарии:

1. 1, но я просто подчеркну, что переменные экземпляра класса отличаются от переменных класса.

2. Кстати, также инкапсуляция ATTR не должна быть ‘read and write’, должна быть просто ‘read’: class << self; attr_reader:var; end И даже это не является подходящим решением для данного случая

3. @Julian не уверен, что вы имеете в виду, это всего лишь пример, и вы можете использовать attr_accessor или attr_reader в зависимости от вашего варианта использования

Ответ №4:

Вы также можете инициализировать значение в определении модуля:

 module MyModule
  class << self
    attr_accessor :my_variable
  end
  self.my_variable = 2   2
end

p MyModule.my_variable
  

Комментарии:

1. Я не рекомендовал изменять переменную класса, это нарушает правила инкапсуляции. Также не соответствует принципу открытия / закрытия из SOLID

2. @julian Это создает переменную экземпляра класса (поскольку модули являются классами), верно? Не уверен, как это нарушает инкапсуляцию…

3. Метапрограммирование — это антишаблон, который нарушает принцип инкапсуляции.