美文网首页
instance(class)_eval(exec)详解

instance(class)_eval(exec)详解

作者: SecondRocker | 来源:发表于2015-06-08 01:38 被阅读352次

    对于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/

    相关文章

      网友评论

          本文标题:instance(class)_eval(exec)详解

          本文链接:https://www.haomeiwen.com/subject/fkxqtttx.html