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

omn*_*nse 2 ruby class-variables

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

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

我知道我可以编写自己的方法来修复方法名称长度问题,我的'方法名称问题'和参数 -as -a-string thingy,但我真正想知道的是:有更好,更短,发烧友,但原生,class_eval提取类变量的方式?

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

编辑:更新问题更具体.

谢谢!

Phr*_*ogz 8

使用class_variable_get,但仅限于必须使用

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

为要访问的变量创建访问器方法

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

class Foo
  def self.bar
    @@bar
  end
end
p Foo.bar
Run Code Online (Sandbox Code Playgroud)

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

class Foo
  class << self
    attr_accessor :bar
  end
end

Foo.bar = 42
p Foo.bar
Run Code Online (Sandbox Code Playgroud)

类变量的行为

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

例如,请考虑以下代码:

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>]
Run Code Online (Sandbox Code Playgroud)

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

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>]
Run Code Online (Sandbox Code Playgroud)

通过在类本身上创建实例变量和访问器方法 - 恰好是Class类的实例,类似于类的MyClass = Class.new所有实例(和外部人员)具有共同的,干净的位置来读取/写入不共享的信息其他课程之间.

请注意,显式跟踪创建的每个实例都会阻止"未使用"实例上的垃圾回收.请谨慎使用上述代码.

使用class_eval更清洁的方式

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

Foo.class_eval('@@bar') # ugh
Foo.class_eval{ @@bar } # yum
Run Code Online (Sandbox Code Playgroud)