Ruby Metaprogramming:动态实例变量名称

And*_*rew 90 ruby metaprogramming instance-variables

假设我有以下哈希:

{ :foo => 'bar', :baz => 'qux' }
Run Code Online (Sandbox Code Playgroud)

如何动态设置键和值以成为对象中的实例变量...

class Example
  def initialize( hash )
    ... magic happens here...
  end
end
Run Code Online (Sandbox Code Playgroud)

...所以我最终在模型中得到以下内容......

@foo = 'bar'
@baz = 'qux'
Run Code Online (Sandbox Code Playgroud)

Chu*_*uck 165

你正在寻找的方法是instance_variable_set.所以:

hash.each { |name, value| instance_variable_set(name, value) }
Run Code Online (Sandbox Code Playgroud)

或者,更简单地说,

hash.each &method(:instance_variable_set)
Run Code Online (Sandbox Code Playgroud)

如果您的实例变量名称缺少"@"(因为它们在OP的示例中),您将需要添加它们,因此它更像是:

hash.each { |name, value| instance_variable_set("@#{name}", value) }
Run Code Online (Sandbox Code Playgroud)

  • 1.9.3对我没用.我用它来代替`hash.each {| k,v | instance_variable_set( "@#{K}",V)}` (18认同)
  • 爱Ruby的另一个原因 (3认同)

Dig*_*oss 12

h = { :foo => 'bar', :baz => 'qux' }

o = Struct.new(*h.keys).new(*h.values)

o.baz
 => "qux" 
o.foo
 => "bar" 
Run Code Online (Sandbox Code Playgroud)

  • @Andrew:`Struct.new`基于哈希键创建一个新类,然后第二个`new`创建刚创建的类的第一个对象,将其初始化为Hash的值.见http://www.ruby-doc.org/core-1.8.7/classes/Struct.html (3认同)
  • 这实际上是一种非常好的方法,因为这几乎就是Struct的用途. (2认同)
  • 或者使用[OpenStruct](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/ostruct/rdoc/OpenStruct.html).`require'ostruct'; h = {:foo =>'foo'}; o = OpenStruct.new(h); o.foo =='foo'` (2认同)

小智 7

你让我们想哭:)

无论如何,请参阅Object#instance_variable_getObject#instance_variable_set.

快乐的编码.


Asa*_*uhi 5

你也可以使用 send它来阻止用户设置不存在的实例变量:

def initialize(hash)
  hash.each { |key, value| send("#{key}=", value) }
end
Run Code Online (Sandbox Code Playgroud)

send在课堂上使用时会有一个像二传手一样attr_accessor实例变量:

class Example
  attr_accessor :foo, :baz
  def initialize(hash)
    hash.each { |key, value| send("#{key}=", value) }
  end
end
Run Code Online (Sandbox Code Playgroud)