【问题标题】:Is there a better way of doing class_eval() to extract class variables, in Ruby?在 Ruby 中,有没有更好的方法来执行 class_eval() 来提取类变量?
【发布时间】:2011-06-02 15:14:22
【问题描述】:

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

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

我知道我可以编写自己的方法来解决 method-name-length 问题、我的“方法名称问题”和 parameter-being-a-string东西,但我真正想知道的是:有没有更好、更短、更花哨但又原生的方法来使用class_eval 来提取类变量?

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

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

谢谢!

【问题讨论】:

  • 你想做什么可能需要eval?通常有一种方法可以得到你想要的东西而不会弄得那么乱。
  • @tadman 啊,你是对的。我在那里错过了我的问题的重点。我基本上想访问一个类变量。所以,类似于 Class.class_eval('@@yay')

标签: ruby class-variables


【解决方案1】:

使用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,请注意它还有一个块形式,无需解析字符串来评估它:

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

【讨论】:

  • 这个答案写得差不多了,然后看到你贴出来了。不过,可能想添加一些有关其含义的内容。
  • 嗯。好吧,我想我想要一个类变量。如果我希望该变量可以在类的所有实例中访问,我会想要一个吗?另一件事,我不完全确定我是否真正掌握了类变量与您在提供的第二个代码 sn-p 中所做的区别 D:!不过,感谢您的回答。
  • @withadot 我已经更新了答案来解释为什么你可能不想要一个类变量,并包含了一个关于如何最好地利用类实例中的类方法的进一步示例(即@987654335 @)。
  • @Phrogz 长方形的例子堪称神。完美的。而且,这正是我所需要的,实际上。伊利
  • ActiveSupport 为类添加了cattr_accessor,为可能清理大量此类内容的模块添加了mattr_accessor
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多