我个人对此没有任何反对意见,除了事实很长,但真正困扰我的是eval
这个词。
我在JavaScript中做了很多东西我从类似eval的任何东西中运行,就像它是魔鬼一样,我也不喜欢参数是一个字符串的事实(再次,可能是因为它是eval)。
我知道我可以编写自己的方法来修复 method-name-length 问题,我的'方法名称问题'和参数-a-a-string 但是,我真正想知道的是:是否有更好,更短,更漂亮但又本土的方式来class_eval
来提取类变量?
旁注:我知道 class_variable_get()
和 class_variables()
的存在,但它们看起来并不吸引人我;非常长,不是吗?
编辑:将问题更新为更具体。
谢谢!
答案 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