Ruby 元编程:动态实例变量名
Posted
技术标签:
【中文标题】Ruby 元编程:动态实例变量名【英文标题】:Ruby Metaprogramming: dynamic instance variable names 【发布时间】:2011-10-08 04:00:00 【问题描述】:假设我有以下哈希:
:foo => 'bar', :baz => 'qux'
如何动态设置键和值成为对象中的实例变量...
class Example
def initialize( hash )
... magic happens here...
end
end
...所以我最终在模型中得到以下内容...
@foo = 'bar'
@baz = 'qux'
?
【问题讨论】:
【参考方案1】:你让我们想哭:)
无论如何,请参阅Object#instance_variable_get
和Object#instance_variable_set
。
编码愉快。
【讨论】:
呃是的,我不禁想知道......为什么?什么时候用这个比较合适? 例如,我可能希望对所有控制器都有一个通用的set_entity
回调,并且我不想干扰现有的实例变量def set_entity(name, model); instance_variable_set(name, model.find_by(params[:id])); end;
【参考方案2】:
您要查找的方法是instance_variable_set
。所以:
hash.each |name, value| instance_variable_set(name, value)
或者,更简单地说,
hash.each &method(:instance_variable_set)
如果您的实例变量名称缺少“@”(就像在 OP 的示例中一样),您需要添加它们,所以它更像是:
hash.each |name, value| instance_variable_set("@#name", value)
【讨论】:
在 1.9.3 中对我不起作用。我用这个代替hash.each |k,v| instance_variable_set("@#k",v)
又一个喜欢 Ruby 的理由
你能解释一下hash.each &method(:instance_variable_set)
中的instance_variable_set
方法如何接收它需要的两个参数吗?
知道如何递归地执行此操作吗? (如果输入哈希中有多个级别)【参考方案3】:
h = :foo => 'bar', :baz => 'qux'
o = Struct.new(*h.keys).new(*h.values)
o.baz
=> "qux"
o.foo
=> "bar"
【讨论】:
这很有趣...第二个链式.new()
到底在做什么?
@Andrew: Struct.new
基于哈希键创建一个新类,然后第二个new
使刚刚创建的类的第一个对象,将其初始化为哈希值.见ruby-doc.org/core-1.8.7/classes/Struct.html
这实际上是一个非常好的方法,因为这几乎就是 Struct 的用途。
或使用OpenStruct。 require 'ostruct'; h = :foo => 'foo'; o = OpenStruct.new(h); o.foo == 'foo'
我必须将我的键映射到符号:Struct.new(*hash.keys.map |str| str.to_sym ).new(*hash.values)
【参考方案4】:
您还可以使用send
来防止用户设置不存在的实例变量:
def initialize(hash)
hash.each |key, value| send("#key=", value)
end
当你的类中有一个像 attr_accessor
这样的 setter 用于你的实例变量时,使用 send
:
class Example
attr_accessor :foo, :baz
def initialize(hash)
hash.each |key, value| send("#key=", value)
end
end
【讨论】:
以上是关于Ruby 元编程:动态实例变量名的主要内容,如果未能解决你的问题,请参考以下文章