在Ruby中有没有更好的方法来运行class_eval()来提取类变量?

时间:2011-06-02 15:14:22

标签: ruby class-variables

我个人对此没有任何反对意见,除了事实很长,但真正困扰我的是eval这个词。

我在JavaScript中做了很多东西我从类似eval的任何东西中运行,就像它是魔鬼一样,我也不喜欢参数是一个字符串的事实(再次,可能是因为它是eval)。

我知道我可以编写自己的方法来修复 method-name-length 问题,我的'方法名称问题'和参数-a-a-string 但是,我真正想知道的是:是否有更好,更短,更漂亮但又本土的方式来class_eval来提取类变量?

旁注:我知道 class_variable_get() class_variables() 的存在,但它们看起来并不吸引人我;非常长,不是吗?

编辑:将问题更新为更具体。

谢谢!

1 个答案:

答案 0 :(得分:8)

使用class_variable_get,但仅限于

class_variable_get 更好的方式,除了它不是“吸引”你的事实。如果你进入一个类并打破封装,也许有这个额外的障碍来表明你做错了。

为要访问的变量

创建访问器方法

如果这些是您的类,并且访问变量不会破坏封装,那么您应该为它们创建类访问器方法,以使其更容易和更漂亮:

class Foo
  def self.bar
    @@bar
  end
end
p Foo.bar

但是,如果这是您的课程,您确定需要类变量吗?如果你不理解其含义(见下文),你可能实际上想要类本身的实例变量:

class Foo
  class << self
    attr_accessor :bar
  end
end

Foo.bar = 42
p Foo.bar

类变量的行为

类变量对于新手而言似乎是在类级别存储信息的正确方式,主要是因为名称。它们也很方便,因为无论您是在类的方法还是实例方法中,都可以使用相同的语法来读取和写入它们。但是,类变量在类及其所有子类之间共享。

例如,请考虑以下代码:

class Rectangle
  def self.instances
    @@instances ||= []
  end
  def initialize
    (@@instances ||= []) << self
  end
end

class Square < Rectangle
  def initialize
    super
  end
end

2.times{ Rectangle.new }
p Rectangle.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>]

Square.new
p Square.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>, #<Square:0x25c76d0>]

的Ack!矩形不是正方形!这是做同样事情的更好方法:

class Rectangle
  def self.instances
    @instances ||= []
  end
  def initialize
    self.class.instances << self
  end
end

class Square < Rectangle
  def initialize
    super
  end
end

2.times{ Rectangle.new }
p Rectangle.instances
#=> [#<Rectangle:0x25c7808>, #<Rectangle:0x25c77d8>]

2.times{ Square.new }
p Square.instances
#=> [#<Square:0x25c76d0>, #<Square:0x25c76b8>]

通过在类本身上创建实例变量和访问器方法 - 恰好是Class类的实例,类似于MyClass = Class.new - 类(和局外人)的所有实例都有一个通用,干净的位置来读/写其他类之间不共享的信息。

请注意,显式跟踪创建的每个实例都会阻止“未使用”实例上的垃圾回收。请仔细使用上述代码。

以更干净的方式使用class_eval

最后,如果你打算使用class_eval,请注意它也有一个块形式,不需要解析和lex字符串来评估它:

Foo.class_eval('@@bar') # ugh
Foo.class_eval{ @@bar } # yum