Ruby 如何理解元编程中的方法定义?

xwf286 · 2013年07月25日 · 最后由 hello_little_yy 回复于 2013年07月26日 · 3603 次阅读

阅读时要区分:类、类的实例对象、类对象! 如何理解 ruby 中的元编程?yehuda 说搞定一个 self 就 ok 了,我看了,还是有点晕晕乎乎,结合学习 ruby 元编程的那本书,我觉得,关键是搞懂 def 这个关键字。 def 的定义有两种情况(方法的前面有没有前缀:接收者): 一 def method_name 二 def x.method_name

第一种情况, def method_name p "ok" end 会在当前类(用 CurrentClass 表示当前类)中定义一个实例方法(所谓类的实例方法,虽然是定义在存放在类中,但类自己不能调用,只能 new 一个实例才能调用)即: CurrentClass.method_name #=> undefined CurrentClass.new.method_name #=> ok

第二种情况, def x.method_name end 会定义一个单件方法,即属于 x 的单件方法,x 是什么,x 就是对象,在这里不管是 myob、MyClass、self 还是什么其他的什么对象,可以是一般对象,也可以是类对象,总之是一个对象。我们知道方法只能放在类中,所以这个单件方法会放在 x 的单件类(大家都知道这个单件类藏起来了)中。

class Myclass def method1 p "method1" end def self.method2 p "method2" end

def Myclass.method3 p "method3" end class<<Myclass def method4 p "method4" end end class<<self def method5 p "method5" end end end

上面这几个方法定义中,method1,method2 和 method3 无需解释,method4 和 method5 要琢磨一下,这两个方法属于第一种情况,没有前缀,是一个普通的实例方法,关键是看当前类是什么,还是 Myclass 吗?

class<<X 我这个位置很特殊 end 就是进入 X 的单件类的作用域中,“我这个位置很特殊” 这里的当前类就是 X 的单件类。补充一句,X 是个对象。 而上述定义 method4 和 method5 的地方正好是位于 Myclass 类对象的单件类之内,而不是 Myclass 类对象本身,所以 method4 和 method5 也就很好理解了,这两个方法的接受者是类(Myclass 类对象的单件类)的实例对象(也就是 Myclass 类对象), 所以这里定义的两个方法恰好是 MyClass 的类方法。

实在是拗口,不知道我有没有说清楚。 总结一句话的话,要看 def 前面有没有内容,如果没有,就是纯真的方法定义,要看当前类是什么,最终就是是这个当前类的实例方法;如果有前缀 x.,方法就定义在 x 的单件类中。

再来看两种情况, MyClass.class_eval do def method6 p "method6" end end

MyClass.instance_eval do def method7 p "method7" end end

注意,上述两种情况都属于没有前缀的,所以会纠结在当前类什么这个问题上。 class_eval 会修改当前类,在这里,当前类就是 Myclass,所以 method 的存放位置就在 Myclass 中,这个方法就一个实例方法。 instance_eval 呢?我们知道这个方法会修改当前对象(即 self),但是会修改当前类吗,答案是会!在 MyClass.instance_eval 中, 当前类是 MyClass 的单件类,所以呢,这个方法是一个类方法。

参考文献: http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/ 另加: http://yugui.jp/articles/846(这篇和我说的意思比较接近)

补充一点:许多情况下,当前类和当前对象(即 self)是一致的,但也有时候也会有差别: 例如: class MyClass def method1 end def self.method2 end end 在这里,当前类和当前对象是一致的,即都是 MyClass,定义方法时声明接收者的话,方法就会定义在当前对象的单件类中,不声明接收者的话,方法就会定义在当前类中。

但在 X.instance_eval 中,当前对象和当前类是不一样的,当前对象是 X,而当前类则是 X 的单件类,从而导致: class MyClass end MyClass.instance_eval do def method1 end def self.method2 end end 中,method1 和 method 都是 MyClass 的类方法。。

对于 yehuda 那种大师,就好像一位气功大师对你说,气功就是所谓的 ‘气’。 你怎么理解 ‘气’ 这个概念,应该是对深入了解以后才明白, 所谓的 ‘气’ 原来是个总结归纳。 所谓的 “self” 也一样。

我觉得理解元编程,应该从三个方面来: 1 理解 ruby 的方法调用,实际上就是一个消息传递, self,就是指 receiver,你应该知道什么情况下,谁是那个消息的 receiver。 2 方法调用链。 你应该了解 Ruby 中方法寻找的过程。 3 理解 Ruby 中的对象模型以及单例类,了解 Ruby 内建的方法哪些是操作单例类的,比如 extend, 我们可以从 api 文档里面就看到了,它是操作单例类的。

从以上三个层面着手,到最后你也会得到一个归纳总结的结论,self。

我这里的理解是光有 sel 还 f 不够,self 是指当前对象,而 ruby 中其实还有一个当前类,当前对象再怎么隐藏还是可以挖出来的,当前类就只能分析代码了。

换句话,搞定 self 的话,方法调用是没问题了,但方法定义的地方还需要琢磨一下当前类是什么

4 楼 已删除
匿名 #5 2013年07月26日

元的意思,就是函数本身也是数据,数据本身也是数据

需要 登录 后方可回复, 如果你还没有账号请 注册新账号