【问题标题】:Why can't I use attr_accessor inside initialize?为什么我不能在初始化中使用 attr_accessor?
【发布时间】:2010-12-16 15:20:26
【问题描述】:

我正在尝试在initialize 中执行instance_eval,然后是attr_accessor,并且我不断收到以下信息:“初始化”:未定义的方法“attr_accessor”。为什么这不起作用?

代码看起来像这样:

class MyClass
   def initialize(*args)
      instance_eval "attr_accessor :#{sym}"
   end
end

【问题讨论】:

    标签: ruby metaprogramming eval


    【解决方案1】:

    Rob d'Apice 几乎正确。你只需要写:

    self.singleton_class.send(:attr_accessor, varname)
    

    self.singleton_class.class_eval "attr_accessor :#{varname}"
    

    或者我最喜欢的变种

    self.singleton_class.class_exec do attr_accessor varname end
    

    假设varname的值是一个符号

    【讨论】:

      【解决方案2】:

      更简洁的实现(注意:这会将访问器添加到类的所有实例,而不仅仅是单个实例,请参见下面的 cmets):

      class MyClass
        def initialize(varname)
          self.class.send(:attr_accessor, varname)
        end
      end
      

      【讨论】:

      • 这将访问器定义为MyClass的实例方法。因此,如果您有o1 = MyClass.new(:foo)o2 = MyClass.new(:bar)o1o2 都有foobar 的访问器,这不是预期的行为。
      • 完全正确!这里有我的上船。我将把这个答案留在这里(附上你的评论)给任何可能遇到的人。
      • Rob 的解决方案看起来要干净得多。但我会坚持 sepp2k 的解决方案,只有一个实例的访问器。
      【解决方案3】:

      您不能在实例上调用 attr_accessor,因为 attr_accessor 未定义为 MyClass 的实例方法。它仅适用于模块和类。我怀疑您想在实例的元类上调用 attr_accessor,如下所示:

      class MyClass
        def initialize(varname)
          class <<self
            self
          end.class_eval do
            attr_accessor varname
          end
        end
      end
      
      o1 = MyClass.new(:foo)
      o2 = MyClass.new(:bar)
      o1.foo = "foo" # works
      o2.bar = "bar" # works
      o2.foo = "baz" # does not work
      

      【讨论】:

      • class_eval 和把它放在你写self的地方是一样的
      • 不,不是。 class &lt;&lt;self; ...;end 不是闭包。您将无法访问其中的varname,但您可以在class_eval 块中访问它。
      • semiomant's answer 很好。看看吧。
      猜你喜欢
      • 2020-08-01
      • 1970-01-01
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多