Як я можу ініціалізувати змінні екземпляра модуля в Ruby?


80

У мене є деякі модулі, де я хотів би використовувати змінні екземпляра. На даний момент я їх ініціалізую так:

module MyModule
  def self.method_a(param)
    @var ||= 0
    # other logic goes here
  end
end

Я також міг би викликати метод init для їх ініціалізації:

def init
  @var = 0
end

але це означало б, що я повинен пам’ятати, щоб завжди називати це.

Чи є кращий спосіб зробити це?


3
Чи не встановлює перший блок коду змінну екземпляра модуля (змінну в межах об'єкта типу MyModule), тоді як другий встановлює "звичайний" екземпляр var (змінну в області екземпляра, що включав модуль)? Я думаю, що ці два блоки коду не роблять одне і те ж ...
Борис Б.

Відповіді:


109

Ініціалізуйте їх у визначенні модуля.

module MyModule
  # self here is MyModule
  @species = "frog"
  @color = "red polka-dotted"
  @log = []

  def self.log(msg)
    # self here is still MyModule, so the instance variables are still available
    @log << msg
  end
  def self.show_log
    puts @log.map { |m| "A #@color #@species says #{m.inspect}" }
  end
end

MyModule.log "I like cheese."
MyModule.log "There's no mop!"
MyModule.show_log #=> A red polka-dotted frog says "I like cheese."
                  #   A red polka-dotted frog says "There's no mop!"

Це встановить змінні екземпляра, коли модуль визначений. Пам'ятайте, ви можете alwasys знову відкрити модуль пізніше, щоб додати більше змінних примірника та визначень методів, або перевизначити існуючі:

# continued from above...
module MyModule
  @verb = "shouts"
  def self.show_log
    puts @log.map { |m| "A #@color #@species #@verb #{m.inspect}" }
  end
end
MyModule.log "What's going on?"
MyModule.show_log #=> A red polka-dotted frog shouts "I like cheese."
                  #   A red polka-dotted frog shouts "There's no mop!"
                  #   A red polka-dotted frog shouts "What's going on?"

12
Минув якийсь час, але так :). Крім того, я відчуваю, що все, що потрібно сказати про панів Фу і Бар, було сказано.
чемпіон

Тож на даний момент не змінні екземпляра, а методи екземпляра?
nipponese 02

nipponese: що не є змінними екземпляра?
чемпіон

5

Ви можете використовувати:

def init(var=0)
 @var = var
end

І за замовчуванням 0, якщо ви нічого не передасте.

Якщо ви не хочете викликати його щоразу, ви можете використати щось подібне:

module AppConfiguration
   mattr_accessor :google_api_key
   self.google_api_key = "123456789"
...

end

Отже, мені все одно потрібно викликати цю функцію, перш ніж робити щось із модулем?
Geo

Я додав 2-й спосіб уникнути цієї проблеми - з коду рейок
Брайан

2

для класу я б сказав наступне, оскільки ініціалізація викликається щоразу, коли ви .новий новий екземпляр класу.

def initialize
   @var = 0
end

від Practical Ruby :

Далі йдеться про те, що ініціалізація модуля буде викликана, якщо ініціалізація класу, що включає, викликає супер, але не згадує, що це наслідок того, як супер працює скрізь, а не спеціальна обробка для ініціалізації. (Чому можна припустити, що ініціалізація отримує особливу обробку? Тому що вона отримує особливу обробку щодо видимості. Особливі випадки створюють плутанину.)


1
Оскільки це модуль, чи буде викликана ініціалізація? Ось якою була моя перша відповідь. Я додав другий, щоб пояснити, що його не викликали.
Брайан

1
OP спеціально згадав модулі, а не класи
Zensaburou

2

я відповів на подібне запитання , ви можете встановити змінні екземпляра класу, роблячи це

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

MyModule.var
=> nil

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

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

2

Очевидно, це погана форма ініціалізації змінних екземпляра в модулі в Ruby. (З причин, яких я не до кінця розумію, але стосуються порядку, в якому речі створюються.)

Здається, найкращою практикою є використання доступу з ледачою ініціалізацією, наприклад:

module MyModule
  def var
    @var ||= 0 
  end
end

Потім використовуйте varяк геттер для @var.


4
Зауважте, це ніколи не дозволить вам встановити для @var значення nilorfalse
steel
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.