#ruby
#ruby
Вопрос:
Как я могу установить некоторые переменные экземпляра при extend
редактировании экземпляра таким же образом, как это можно сделать при его создании, с помощью initialize
.
В этом примере переменная, установленная при расширении, «потеряна»:
module Mod
def self.extended(base)
@from_module = "Hello from Mod"
puts "Setting variable to: #{@from_module}"
end
def hello_from_module
return @from_module
end
end
class Klass
def initialize
@from_class = "Hello from Klass"
end
def hello_from_class
return @from_class
end
end
klass = Klass.new #=> #<Klass:0x00000000ed8618 @from_class="Hello from Klass">
klass.extend(Mod) #=> #<Klass:0x00000000ed8618 @from_class="Hello from Klass">
"Setting variable to: Hello from Mod"
klass.hello_from_class #=> "Hello from Klass"
klass.hello_from_module #=> nil (warning: instance variable @from_module not initialized)
Комментарии:
1. Переменная не потеряна. Переменные экземпляра принадлежат объектам (instances), вот почему они называются переменными экземпляра. Для какого экземпляра вы устанавливаете переменную? Ну, метод является одноэлементным методом
Mod
, поэтомуself
являетсяMod
и переменная экземпляра является переменной экземпляраMod
.2. Стоит отметить, что
return
неявно в Ruby, последнее, что остается в стеке, — это возвращаемое значение по умолчанию, поэтому его обычно можно опустить, если последнее, что вы хотите получить в методе в качестве возвращаемого значения.
Ответ №1:
Существует несколько способов сделать то, что вы описываете.
Наиболее распространенным из них было бы использование instance_variable_get
и instance_variable_set
:
module ModA
def self.extended(base)
base.instance_variable_set(:@from_module, "Hello from Mod A")
puts "Setting variable to: #{base.instance_variable_get(:@from_module)}"
end
def hello_from_module
return @from_module
end
end
Другой распространенный метод заключается в использовании любого из методов eval
или exec
. В этом случае instance_exec
:
module ModB
def self.extended(base)
base.instance_exec { @from_module = "Hello from Mod B" }
puts "Setting variable to: #{base.instance_exec { @from_module }}"
end
def hello_from_module
return @from_module
end
end