当前位置:  开发笔记 > 编程语言 > 正文

在Ruby中将实例变量添加到类中

如何解决《在Ruby中将实例变量添加到类中》经验,为你挑选了3个好方法。

如何在运行时将实例变量添加到已定义的类,然后从类外部获取并设置其值?

我正在寻找一种元编程解决方案,它允许我在运行时修改类实例,而不是修改最初定义类的源代码.一些解决方案解释了如何在类定义中声明实例变量,但这不是我所要求的.



1> Gordon Wilso..:

Ruby为此提供了方法,instance_variable_getinstance_variable_set.(docs)

您可以创建和分配新的实例变量,如下所示:

>> foo = Object.new
=> #

>> foo.instance_variable_set(:@bar, "baz")
=> "baz"

>> foo.inspect
=> #


迈克,我认为这是这个问题的实际目标.他正在询问如何在运行时添加变量,因此使用instance_variable_set而不是在代码中定义它.很可能"baz"也是另一个变量.

2> Mike Stone..:

您可以使用属性访问器:

class Array
  attr_accessor :var
end

现在您可以通过以下方式访问它

array = []
array.var = 123
puts array.var

请注意,您也可以使用attr_readerattr_writer仅定义getter或setter,或者您可以手动定义它们:

class Array
  attr_reader :getter_only_method
  attr_writer :setter_only_method

  # Manual definitions equivalent to using attr_reader/writer/accessor
  def var
    @var
  end

  def var=(value)
    @var = value
  end
end

如果您只想在单个实例上定义它,也可以使用单例方法:

array = []

def array.var
  @var
end

def array.var=(value)
  @var = value
end

array.var = 123
puts array.var

仅供参考,对于这个答案的评论,单例方法工作正常,以下是证明:

irb(main):001:0> class A
irb(main):002:1>   attr_accessor :b
irb(main):003:1> end
=> nil
irb(main):004:0> a = A.new
=> #
irb(main):005:0> a.b = 1
=> 1
irb(main):006:0> a.b
=> 1
irb(main):007:0> def a.setit=(value)
irb(main):008:1>   @b = value
irb(main):009:1> end
=> nil
irb(main):010:0> a.setit = 2
=> 2
irb(main):011:0> a.b
=> 2
irb(main):012:0> 

正如您所看到的,单例方法setit将设置相同的字段,@b就像使用attr_accessor定义的那样...因此单例方法是解决此问题的完美有效方法.



3> Mike Stone..:

@ Readonly

如果您使用"class MyObject"是使用open类,那么请注意您正在重新定义initialize方法.

在Ruby中,没有重载...只有覆盖或重新定义......换句话说,任何给定方法只能有1个实例,所以如果重新定义它,它将被重新定义...并初始化方法没有什么不同(即使它是Class对象使用的新方法).

因此,永远不要重新定义现有方法而不先将其别名化......至少如果您想要访问原始定义.重新定义未知类的初始化方法可能非常危险.

无论如何,我认为我有一个更简单的解决方案,它使用实际的元类来定义单例方法:

m = MyObject.new
metaclass = class << m; self; end
metaclass.send :attr_accessor, :first, :second
m.first = "first"
m.second = "second"
puts m.first, m.second

您可以同时使用元类和开放类来实现更复杂的操作,并执行以下操作:

class MyObject
  def metaclass
    class << self
      self
    end
  end

  def define_attributes(hash)
    hash.each_pair { |key, value|
      metaclass.send :attr_accessor, key
      send "#{key}=".to_sym, value
    }
  end
end

m = MyObject.new
m.define_attributes({ :first => "first", :second => "second" })

以上基本上是通过"元类"方法公开元类,然后在define_attributes中使用它来动态定义一组带有attr_accessor的属性,然后使用哈希中的相关值调用属性setter.

使用Ruby,您可以获得创造性并以不同的方式做同样的事情;-)


仅供参考,如果您不知道,使用元类就像我所做的那样,意味着您只对该对象的给定实例进行操作.因此,调用define_attributes将仅定义该特定实例的那些属性.

例:

m1 = MyObject.new
m2 = MyObject.new
m1.define_attributes({:a => 123, :b => 321})
m2.define_attributes({:c => "abc", :d => "zxy"})
puts m1.a, m1.b, m2.c, m2.d # this will work
m1.c = 5 # this will fail because c= is not defined on m1!
m2.a = 5 # this will fail because a= is not defined on m2!

推荐阅读
yzh148448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有