为了答谢各位新老客户,所以本店将赠送大家装X名字一枚:metaclass(我认为面试ruby的话能说出metaclass跟扁平作用域就能说明你对ruby有一定层次的理解了。)
不过首先呢,我们要知道什么是eigenclass。
本人的一贯工作作风就是脏活累活给别人干,所以我就不在这里介绍eigenclass,大家可以自行baidu或者参考http://17test.info/?p=152。
知道了eigenclass了,再告诉你下一个秘密:定义class跟定义方法一样,都有返回值!
turth = class A "The most xun national wind" end puts turth
虽然在class里不能用return,但是最后一句表达式的值却真的有返回。
终于要到正题了:创建类方法。
在class_eval里直接用define_method显然是不行的,define_method只能添加实例方法,但是正如我们第三篇所说,类方法就是这个类作为一个对象(Class的实例)的实例方法,所以只要我们找到这个类的类(我已经厌倦了这种表达……),然后添加实例方法即可……
Klass = Class.new Klass.class_eval do define_method :instance_method_for_demo do puts "This is a instance method for #{self}" end self.class.class_eval do define_method :class_method_for_demo do puts "This is a class method for #{self}" end end end Klass.new.instance_method_for_demo Klass.class_method_for_demo
哈哈大功告成。
不过这样做是不对的。
虽然给Klass添加好了类方法,但是突然发现,所有类都多了一个类方法……
Array.class_method_for_demo
String.class_method_for_demo
因为上面代码中self.class就是Class,所有的类都是Class的子类,所以上面的代码相当于给每一个类都添加了一个方法……what the fxxk
说脏话显然是解决不了问题的,要解决问题首先要知道——问题是什么……
我们需要在Class里添加一个实例方法,但是我希望这个Class只属于我们的Klass……
那么,有没有只属于我们的Klass的Class呢?
eigenclass,该你出场了。
metaclass = (class << self;self;end)
这句代码单独拿出来不好理解,因为我们不知道self是什么,那我们就放进上下文中。
Klass = Class.new Klass.class_eval do define_method :instance_method_for_demo do puts "This is a instance method for #{self}" end metaclass = (class << self; self; end) metaclass.class_eval do define_method :class_method_for_demo do puts "This is a class method for #{self}" end end end Klass.new.instance_method_for_demo Klass.class_method_for_demo Array.class_method_for_demo String.class_method_for_demo
到了这里我已经感觉无力解释了,只能提示一下:metaclass = (class << self; self; end)
这里面虽然有两个self,但是这两个self是不一样的……
即时还是不理解,先记住结论:在metaclass.class_eval里define_method,就可以添加类方法。