2

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

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

我知道我可以编写自己的方法来解决方法名称长度问题、我的“方法名称问题”和参数存在字符串的问题,但我真正想知道的是:有没有更好、更短的方法,更漂亮,但更原生的class_eval提取类变量的方法?

旁注:我知道 and 的存在 class_variable_get() class_variables()但它们对我来说并不吸引人;可怕的长,不是吗?

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

谢谢!

4

1 回答 1

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>]

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

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
于 2011-06-02T15:30:48.087 回答