Объявление переменных экземпляра, перебирающих хеш!
-
06-07-2019 - |
Вопрос
я хочу сделать следующее:
Я хочу объявить переменные экземпляра класса, перебирающего словарь.
Предположим, что у меня есть этот хэш
hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
и я хочу, чтобы каждый ключ был переменной экземпляра класса.Я хочу знать, могу ли я объявить переменные, перебирающие этот хеш.Что-то вроде этого:
class MyClass
def initialize()
hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
hash.each do |k,v|
@k = v
end
end
end
Я знаю, что это не работает! Я добавил этот фрагмент кода только для того, чтобы посмотреть, сможете ли вы более четко понять, чего я хочу.
Спасибо!
Решение
class MyClass
def initialize()
hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
hash.each do |k,v|
instance_variable_set("@#{k}",v)
# if you want accessors:
eigenclass = class<<self; self; end
eigenclass.class_eval do
attr_accessor k
end
end
end
end
Собственный класс — это специальный класс, принадлежащий только одному объекту, поэтому определенные там методы будут методами экземпляра этого объекта, но не принадлежат другим экземплярам обычного класса объекта.
Другие советы
class MyClass
def initialize
# define a hash and then
hash.each do |k,v|
# attr_accessor k # optional
instance_variable_set(:"@#{k}", v)
end
end
end
Ответ Чака лучше, чем мои последние две попытки.Собственный класс не self.class
как я и думал;Чтобы понять это, потребовался тест получше, чем я написал.
Используя свой старый код, я провел тестирование следующим образом и обнаружил, что действительно манипулировали классом, а не экземпляром:
a = MyClass.new :my_attr => 3
b = MyClass.new :my_other_attr => 4
puts "Common methods between a & b:"
c = (a.public_methods | b.public_methods).select { |v| a.respond_to?(v) && b.respond_to?(v) && !Object.respond_to?(v) }
c.each { |v| puts " #{v}" }
Результат был:
Common methods between a & b:
my_other_attr=
my_attr
my_attr=
my_other_attr
Это явно опровергает мое предположение.Мои извинения, Чак, ты были все время правильно.
Старый ответ:
attr_accessor
работает только при оценке в определении класса, а не при инициализации экземпляра.Поэтому единственный способ напрямую сделать то, что вы хотите, — это использовать instance_eval
со строкой:
class MyClass
def initialize(params)
#hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
params.each do |k,v|
instance_variable_set("@#{k}", v)
instance_eval %{
def #{k}
instance_variable_get("@#{k}")
end
def #{k}= (new_val)
instance_variable_set("@#{k}", new_val)
end
}
end
end
end
Чтобы проверить это, попробуйте:
c = MyClass.new :my_var => 1
puts c.my_var
http://facets.rubyforge.org/apidoc/api/more/classes/OpenStructable.html
OpenStructable - это модуль микшина, который может обеспечить поведение открытия для любого класса или объекта.OpenStructable позволяет расширить объекты данных с помощью произвольных атрибутов.