instance(class)_eval(exec)详解

对于instance_eval和class_eval,在看ruby元编程时以为搞清楚了,但最近发现一种情况,却又让我迷糊了:
class_eval

class A
end
A.class_eval
  def a
    puts 'a'
  end
  define_method :b do
    puts 'b'
  end
end
A.new.a # 'a'
A.new.b # 'b'
#a和b都是A的实例方法

instance_eval

class A
end
A.instance_eval do
  def a
    puts 'a'
  end
  define_method :b do
    puts 'b'
  end
end
A.new.b # 'b' b为实例方法
A.new.a #  no method error!!!
A.a # ‘a’

为什么在instance_eval中 def 和define_method定义的一个为类方法(类的单件方法) 一个为实例方法呢?

要解释这个问题,首先要有以下概念:
ruby在执行时,会一直追踪当前对象(receiver)即self,但也会追踪当前类(current class)。instance_eval和class_eval都会修改self和current class:

  • klass.class_eval 修改self为klass,修改current class为klass
  • obj.instance_eval 修改self为obj,修改current class为
    obj的eigen_class(singleton_class)。

了解了以上知识,我们知道define_method的接受者为self,class_eval和instance_eval都改变self为调用者本身,所以定义的为实例方法;而对def起作用的是当前类(current class),class_eval修改当前类为调用者本身,所以定义的是实例方法,而instance_eval修改当前类为调用者的eigen_class(singleton_class),所以定义的是类方法(类的单件方法)。

另外,class_eval仅类可调用,instance_eval则类和对象都可调用。

class(instance)_exec与eval基本相似,但有以下不同:

  • _eval 既可传递字符串,也可传递块,如123.instance_eval 'to_s'
  • _exec只能传递快、不能传字符串,但_exec可以为block传递参数如 Class.instance_exec('Self'){|x|p "#{x}:self"}

至此,class_eval,instance_eval,instance_exec,instance_eval概念基本都透彻了。
对于current class有些未说清的(未研究透彻,初步判断current class 对关键字起作用,self对方法调用起作用~),回头研究完单写一篇。

转载请注明出处: http://me.angry-arthas.com/blog/2015/06/07/instance-ev-instance-exec-class-eval-class-exec-qu-bie/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,814评论 0 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,026评论 19 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,785评论 18 399
  • 大自然的造化我们谁也捉摸不透,大自然的神奇我们谁都只能叹为观止,大自然的神秘我们无能为力。哪怕,明知生死攸关,我们...
    若木菡阅读 2,284评论 51 87
  • 时间真的会改变一个人。 我只能很没用的说起曾经,现在已不能知道也不能体会当时的所感所想,同样也不能后悔当时的任何决...
    白兔兔阅读 277评论 0 0