class << self; self; end
这段代码,每个Rubyist应该都很熟悉。
但是这里面的self是什么? singleton_class? meta_class? eigen_class?
在早期,确切来说应该是Ruby1.9.2发布之前,Ruby社区关于以上这段代码的命名,有很大的争议,后来Ruby团队准备在1.9.2中增加一个方法,来消除这种命名的争议。 这个名字除了Ruby官方的统一之外,更重要的是为了方便Rubyist去使用。比如,1.9.2之前的代码:
(class << self; self; end).class_eval do
define_method meth do |*args|
subject.send meth, *args
end
end
或者有更优雅的写法:
def metaclass
class << self; self; end
end
metaclass.class_eval do
define_method meth do |*args|
subject.send meth, *args
end
end
这个metaclass是社区里其中一个命名,还有命名为eigen_class的, 在Ruby内部,被命名为virtual class, 有代码为证:
#ruby 1.8.7
class User
class << self
puts self
puts self.new
end
end
#=> #<Class:User>
#=> TypeError: can't create instance of virtual class
报错的信息显示,Ruby内部称之为:virtual class。
当然,在Ruby1.9.2之后, 确定了名字,叫做singleton_class, 代码为证:
class User
class << self
puts self
puts self.new
end
end
#=> #<Class:User>
#=> TypeError: can't create instance of singleton class
并且提供了一个方法,Object#singleton_class, 这是一个短形式,相当于你直接使用(class << self; self; end)
Object.instance_methods.grep(/class|singleton|eigen|meta/)
#=> [:class, :singleton_class, :singleton_methods, :define_singleton_method]
关于这个命名,社区里还是有一些争议的, 可以看这个帖子。
有的人说用metaclass, metaclass翻译成中文就是元类, 意思就是,一个类自己的类,但是明显不符合事实,因为在Ruby中,对于类还可以用这个命名,但是对象呢?每个对象都有这样一个类(class << self; self; end), 自然,metaclass就被否决了。
有的人说用eigen_class,翻译为中文就是本质类,也可以叫固有类,有点偏语义、偏哲学层面,用这个名字其实也可以。但是,在Ruby里已经有了一个方法,叫singleton_methods,专门用于查看eigen_class这样的类中定义的方法, 难道要把singleton_methods改称eigen_methods吗? 或者叫eigenclass? eigenmethods? 就这样Ruby核心团队陷入了深深的困扰中。
其实最受欢迎的命名还是singleton_class, 但是这个命名有很大的歧义,那就是容易让人联想到设计模式 - 单例模式上面去。不知道这个设计模式的还好,知道这个设计模式的,第一印象就以为是单例模式,尤其是国内,把singleton_class翻译为单例类让人更加困扰,但实际上,这个singleton_class和单例模式没有什么关系, 我们只能从这个命名的英文含义去理解, 个人认为中文翻译为单例类不太好,应该翻译为单类,因为singleton_class是指Ruby中每个对象都对应的那个特殊的类,就像影子一样跟着Ruby中的每一个对象,形单影只,所以有人也把它叫做影子类。 所以,这些因素都是Ruby团队需要考虑的。
但是最后的决定,还是用了singleton_class,因为Ruby团队不想去改已经实现的singleton_methods等带着singleton_前缀的方法了。
这里提一下,「Ruby元编程」中用的是eigenclass,作者说对于这个名字,官方并未定论,按理说在他写这本书之前,应该1.9.2还未发布,但是2011年这本书出版的时候,Ruby1.9.2应该早出版了,singleton_class应该就是官方对于(class << self; self; end)的定论了。
值得一提的是,Ruby标准库里有一个Singleton Moudle,这个才是真正用于去实现单例模式的。
那么现在,我们要动态的创建一个类或对象的方法,可以方便的去使用singleton_class了:
singleton_class.class_eval do
define_method meth do |*args|
subject.send meth, *args
end
end
关于singleton class的更多示例:
class User
def self.name
puts "hello"
end
class << self
def age
puts "18 years old"
end
end
end
User.singleton_methods #=> [:name, :age]
user = User.new
def user.lover
puts "kitty"
end
user.singleton_methods #=> [:lover]
other_user = User.new
other_user.singleton_methods #=> []
class Admin < User
end
Admin.singleton_methods #=> [:name, :age]