如何为动态实例变量设置attr_accessor?

eyw*_*ywu 31 ruby instance-variables attr-accessor attr

我在我的类中动态创建了一个实例变量:

class Mine
  attr_accessor :some_var

  def intialize
    @some_var = true
  end

  def my_number num
    self.instance_variable_set "@my_#{num}", num
  end
end
Run Code Online (Sandbox Code Playgroud)

@my_#{num}现在如何制作attr值?

例如,我希望能够这样做:

dude = Mine.new
dude.my_number 1
dude.my_1
=> 1
Run Code Online (Sandbox Code Playgroud)

Orl*_*ndo 27

这个答案没有污染类空间,例如..如果我这样做,mine.my_number 4那么其他实例Mine将不会得到my_4方法..这是因为我们使用对象的单例类而不是类.

class Mine
  def my_number num
    singleton_class.class_eval { attr_accessor "my_#{num}" }
    send("my_#{num}=", num)
  end
end

a = Mine.new
b = Mine.new
a.my_number 10 #=> 10
a.my_10 #=> 10
b.my_10 #=> NoMethodError
Run Code Online (Sandbox Code Playgroud)

  • @HalilÖzgür 您只想为该实例定义该方法,所以这就是您使用 `singleton_class` 的原因,如果您使用 `self.class`,那么所有实例都会获得该方法,而您不希望那样。你的语法是对的,我会做出改变 (2认同)

Dor*_*ime 24

这可以使用__send__.这里:

class Mine
  attr_accessor :some_var

  def intialize
    @some_var = true
  end

  def my_number num
    self.class.__send__(:attr_accessor, "my_#{num}")
    self.__send__("my_#{num}=", num)
  end
end

dude = Mine.new
dude.my_number 1
puts dude.my_1

=> 1
Run Code Online (Sandbox Code Playgroud)

  • 这将在所有实例上定义访问器,而不仅仅是您称为"my_number"的实例.我添加了一个额外的答案,只为您添加实例变量的实例添加方法. (2认同)

Ger*_*rry 10

简单.您可以在my_number方法中动态定义属性读取器:

  def my_number num
     self.instance_variable_set "@my_#{num}", num
     self.class.class_eval do
        define_method("my_#{num}") { num }
     end
  end
Run Code Online (Sandbox Code Playgroud)

看看这是否适合你


And*_*imm 6

您可能想要使用 OpenStruct:

require "ostruct"

class Mine < OpenStruct
end

dude = Mine.new
dude.my_number = 1
dude.my_number # => 1
Run Code Online (Sandbox Code Playgroud)

我不知道你为什么要dude.my_1返回 1 - 这不是把你已经拥有的东西还给你吗?


car*_*iam 5

这里有两个方法存在一个问题......如果在一个实例中设置了一个实例变量,那么它的访问器将可用于所有实例,因为你是在on self.class而不是在self 上定义方法.

dude = Mine.new
dude.my_number 1
puts dude.my_1
dudette = Mine.new
dudette.my_1 = 2    # works, but probably shouldn't
dudette.my_number 2
dude.my_2 = 3       # works, but probably shouldn't
Run Code Online (Sandbox Code Playgroud)

您可能想要做的是仅修改具有实例变量的实例:

class Mine
  # ...
  def my_number num
    class << self
      attr_accessor "my_#{num}"
    end
    self.send("my_#{num}=", num)
  end
end
Run Code Online (Sandbox Code Playgroud)

这样,实例变量只能为它们创建的对象获取访问器.我也没有打扰instance_variable_set,因为如果你正在设置一个访问器,那么我认为重用它会更好.但这是一种风格调用.这里最重要的是打电话class << self而不是self.class.

  • 也不适合我。如果不起作用,请删除您的答案。 (2认同)