【问题标题】:Ruby Metaprogramming: dynamic instance variable namesRuby 元编程:动态实例变量名
【发布时间】:2011-10-08 04:00:00
【问题描述】:

假设我有以下哈希:

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

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

class Example
  def initialize( hash )
    ... magic happens here...
  end
end

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

@foo = 'bar'
@baz = 'qux'

?

【问题讨论】:

    标签: ruby metaprogramming instance-variables


    【解决方案1】:

    你让我们想哭:)

    无论如何,请参阅Object#instance_variable_getObject#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 的用途。
    • 或使用OpenStructrequire '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
    

    【讨论】:

      猜你喜欢
      • 2012-05-14
      • 1970-01-01
      • 2020-03-01
      • 2014-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-10
      相关资源
      最近更新 更多