【问题标题】:Declaring instance variables iterating over a hash!声明迭代哈希的实例变量!
【发布时间】:2010-12-09 13:37:57
【问题描述】:

我想做以下事情:

我想声明一个遍历字典的类的实例变量。

假设我有这个哈希

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

我知道这行不通!我只是放这段代码,看看你能不能更清楚地理解我想要什么。

谢谢!

【问题讨论】:

    标签: ruby class hash iterator instance-variables


    【解决方案1】:
    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
    

    eigenclass 是一个只属于单个对象的特殊类,因此定义的方法将是该对象的实例方法,但不属于该对象的普通类的其他实例。

    【讨论】:

      【解决方案2】:
      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
      

      【讨论】:

      • 感谢您的可选评论!但是哈希迭代器 BLOCK 中的 attr_accessor 对我不起作用……我该怎么做? (创建 attr_accessors 迭代)
      • 为了做一个attr_accessor,你需要在一个类上下文中。获取实例的类上下文的方法是使用对象的特征类,就像我的回答一样。
      【解决方案3】:

      Chuck 的回答比我最近两次尝试的要好。特征类不像我想的那样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
      

      这显然反驳了我的假设。我很抱歉 Chuck,你一直都是对的。

      旧答案:

      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
      

      【讨论】:

      • self.class不是特征类。修改self.class 将影响属于该类的每个对象,而修改对象的特征类只会影响该对象。它们在某些情况下可以互换,但一般情况下不能互换。
      • 从 1.8.7 开始,我对此进行了测试,发现您的断言是错误的。尽管如此,这是我测试的唯一版本。
      • 那么你的测试有缺陷。运行这个:"Hello".class.class_eval {def size() 9000 end}; puts "Bye".size,你会看到覆盖 "Hello".class 中的方法也会影响完全不相关的字符串 "Bye" 的行为。在您可能遇到的任何 Ruby 版本中都是如此。
      • 我向 Chuck 道歉,更好的测试表明你是正确的。但这似乎没有任何意义,所以我不得不问一个问题。
      【解决方案4】:

      http://facets.rubyforge.org/apidoc/api/more/classes/OpenStructable.html

      OpensStructable 是一个混合模块 可以提供 OpenStruct 行为 到任何类或对象。开放结构 允许扩展数据对象 任意属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-28
        • 1970-01-01
        • 1970-01-01
        • 2018-08-09
        • 2012-03-10
        • 2015-06-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多