#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. Метапрограммирование — это антишаблон, который нарушает принцип инкапсуляции.