用于访问 Ruby 中的 class 方法的动态变量
Dynamic Variables to access class methods in Ruby
在 Ruby 中工作,我们必须使用第 3 方框架,它有一个 class 设置如下:
class Foo
attr_accessor :bar
def initialize()
end
end
class Poorly_Designed_Class
attr_accessor :thing1
attr_accessor :thing2
attr_accessor :thing3
attr_accessor :thing4
attr_accessor :thing5
# through :thing_n .. number defined at runtime
def initialize()
@thing1 = Foo.new
@thing2 = Foo.new
@thing3 = Foo.new
@thing4 = Foo.new
@thing5 = Foo.new
end
end
到运行时才知道有多少"things"。可能有 5 个,也可能有 50 个。
我想做的是:
pdc = Poorly_Designed_Class.new
for i in 0..numberOfThings do
pdc."thing#{i}".bar = value[i]
end
以上方法无效。
我也试过通过以下方式访问它:
instance_variable_set("pdc.thing#{i}.bar",value)
我知道 class 应该使用数组或散列。不幸的是,我无法对 class 的设计方式做任何事情,我们必须使用它。
我想做的事情有可能吗?
您可以尝试调用 getter(最好是,因为它支持封装):
pdc = PoorlyDesignedClass.new
1.upto(number_of_things.times do |i|
pdc.public_send(:"thing#{i}").bar = value[i]
end
或者获取实例变量(不太推荐,因为它破坏了封装):
pdc = PoorlyDesignedClass.new
1.upto(number_of_things) do |i|
pdc.instance_variable_get(:"@thing#{i}").bar = value[i]
end
所以,您的方向是正确的,您的代码只有两个问题:实例变量名称以 @
符号开头,并且 .
不是标识符中的合法字符.
您正在使用 Object#instance_variable_set
incorrectly. The first argument must be a string or a symbol representing the name of an instance variable including the @
prefix: e.g. "@thing{i}"
. However you actually want to get the value of an instance variable and then send #bar=
to it. That can be done with Object#instance_variable_get
:
1.upto(numberOfThings) { |i| pdc.instance_variable_get("@thing#{i}").bar = value[i] }
有点长,因为 attr_acessor :thingX
定义了 getter 方法,通常最好用 Object#public_send
调用它们而不是直接访问实例变量(getter方法可能会做一些事情,而不仅仅是返回一个值):
1.upto(numberOfThings) { |i| pdc.public_send("thing#{i}").bar = value[i] }
在 Ruby 中工作,我们必须使用第 3 方框架,它有一个 class 设置如下:
class Foo
attr_accessor :bar
def initialize()
end
end
class Poorly_Designed_Class
attr_accessor :thing1
attr_accessor :thing2
attr_accessor :thing3
attr_accessor :thing4
attr_accessor :thing5
# through :thing_n .. number defined at runtime
def initialize()
@thing1 = Foo.new
@thing2 = Foo.new
@thing3 = Foo.new
@thing4 = Foo.new
@thing5 = Foo.new
end
end
到运行时才知道有多少"things"。可能有 5 个,也可能有 50 个。
我想做的是:
pdc = Poorly_Designed_Class.new
for i in 0..numberOfThings do
pdc."thing#{i}".bar = value[i]
end
以上方法无效。
我也试过通过以下方式访问它:
instance_variable_set("pdc.thing#{i}.bar",value)
我知道 class 应该使用数组或散列。不幸的是,我无法对 class 的设计方式做任何事情,我们必须使用它。
我想做的事情有可能吗?
您可以尝试调用 getter(最好是,因为它支持封装):
pdc = PoorlyDesignedClass.new
1.upto(number_of_things.times do |i|
pdc.public_send(:"thing#{i}").bar = value[i]
end
或者获取实例变量(不太推荐,因为它破坏了封装):
pdc = PoorlyDesignedClass.new
1.upto(number_of_things) do |i|
pdc.instance_variable_get(:"@thing#{i}").bar = value[i]
end
所以,您的方向是正确的,您的代码只有两个问题:实例变量名称以 @
符号开头,并且 .
不是标识符中的合法字符.
您正在使用 Object#instance_variable_set
incorrectly. The first argument must be a string or a symbol representing the name of an instance variable including the @
prefix: e.g. "@thing{i}"
. However you actually want to get the value of an instance variable and then send #bar=
to it. That can be done with Object#instance_variable_get
:
1.upto(numberOfThings) { |i| pdc.instance_variable_get("@thing#{i}").bar = value[i] }
有点长,因为 attr_acessor :thingX
定义了 getter 方法,通常最好用 Object#public_send
调用它们而不是直接访问实例变量(getter方法可能会做一些事情,而不仅仅是返回一个值):
1.upto(numberOfThings) { |i| pdc.public_send("thing#{i}").bar = value[i] }