详解Ruby中的instance_eval方法及其与class_eval的对比

所属分类: 脚本专栏 / ruby专题 阅读数: 1663
收藏 0 赞 0 分享

instance_eval方法

这个BasicObject#instance_eval有点类似JS中的bind方法,不同的时,bind是将this传入到对象中,而instance_eval则是将代码块(上下文探针Context Probe)传入到指定的对象中,一个是传对象,一个是传执行体。通过这种方式就可以在instance_eval中的代码块里访问到调用者对象中的变量。

示例代码

class MyClass
  def initialize
    @v = 1
  end
end
obj = MyClass.new

obj.instance_eval do
  self  #=> #<MyClass:0x33333 @v=1>
  @v   #=> 1 
end

v = 2
obj.instance_eval { @v = v }
obj.instance_eval { @v }  # => 2

此外,instance_eval方法还有一个双胞胎兄弟:instance_exec方法。相比前者后者更加灵活,允许对代码块传入参数。

示例代码

class C
  def initialize
    @x = 1
  end
end
class D
  def twisted_method
    @y = 2
    #C.new.instance_eval { “@x: #{@x}, @y>: #{y}” }
    C.new.instance_exec(@y) { |y| “@x: #{@x}, @y: #{y}” }
  end
end
#D.new.twisted_method  # => “@x: 1, @y: ”
D.new.twisted_method  # => “@x: 1, @y: 2”

因为调用instance_eval后,将调用者作为了当前的self,所以作用域更换到了class C中,之前的作用域就不生效了。这时如果还想访问到之前@y变量,就需要通过参数打包上@y一起随instance_eval转义,但因为instance_eval不能携带参数,所以使用其同胞兄弟instance_exec方法。


instance_eval 与 class_eval 的区别
###instance_eval
首先从名字可以得到的信息是,instance_eval的调用者receiver必须是一个实例instance,而在instance_eval block的内部,self即为receiver实例本身。

obj_instance.instance_eval do
 self # => obj_instance
 # current class => obj_instance's singleton class
end
<!--more-->

根据这个定义,如果在一个实例上调用了instance_eval,就可以在其中定义该实例的单态函数 singleton_method

class A
end

a = A.new
a.instance_eval do
 self # => a
 # current class => a's singleton class
 def method1
  puts 'this is a singleton method of instance a'
 end
end

a.method1
#=> this is a singleton method of instance a

b = A.new
b.method1
#=>NoMethodError: undefined method `method1' for #<A:0x10043ff70>

同样,因为类class本身也是Class类的一个实例,instance_eval也可以用在类上,这个时候就可以在其中定义该类的singleton_method,即为该类的类函数。

换句话说,可以用instance_eval来定义类函数class method,这比较容易混淆,需要搞清楚。

class A
end

A.instance_eval do
 self # => A
 # current class => A's singleton class
 def method1
  puts 'this is a singleton method of class A'
 end
end

A.method1
#=> this is a singleton method of class A
class_eval

###class_eval

再来看class_eval,首先从名字可以得到的信息是,class_eval的调用者receiver必须是一个类,而在class_eval block的内部,self即为receiver类本身。

class A
end

A.class_eval do
 self # => A
 # current class => A
end

根据这个定义,如果在一个类上调用了class_eval,就可以在其中定义该类的实例函数 instance_method

class A
end

a = A.new
a.method1
#=> NoMethodError: undefined method `method1' for #<A:0x10043ff70>

A.class_eval do
 self # => A
 # current class => A
 def method1
  puts 'this is a instance method of class A'
 end
end

a.method1
#=> this is a instance method of class A

换句话说,可以用class_eval来定义实例函数instance method,这也比较容易混淆,需要搞清楚。

更多精彩内容其他人还在看

简要解读Ruby面向对象编程中的作用域

作用域在面向对象编程中是一个十分重要的概念,程序构建时必须要理解清楚类和方法以及对象的作用范围,接下来就为大家简要解读Ruby面向对象编程中的作用域
收藏 0 赞 0 分享

详解Ruby中的instance_eval方法及其与class_eval的对比

Ruby的eval族方法将字符串作为代码来执行,instance_eval方法便是其中之一,下面就来详解Ruby中的instance_eval方法及其与class_eval的对比
收藏 0 赞 0 分享

Ruby程序中正则表达式的基本使用教程

和Python与Perl一样,Ruby对正则表达式的支持也是相当好的,这里送出整理的Ruby程序中正则表达式的基本使用教程,需要的朋友可以参考下
收藏 0 赞 0 分享

Ruby on Rails所构建的应用程序基本目录结构总结

Ruby on Rails是Ruby世界中一家独大的Web开发框架,要掌握Rails程序的构建,对其目录结构的了解十分必要,下面就来看一下Ruby on Rails所构建的应用程序基本目录结构总结
收藏 0 赞 0 分享

Ruby中的gem包管理的使用及gem源搭建教程

RubyGems是Ruby世界中的包管理工具,gem命令使用起来就如同Linux中的apt与yum一样,也可以构建自己的gem源,下面就带大家一起来学习Ruby中的gem包管理的使用及gem源搭建教程
收藏 0 赞 0 分享

Linux下Redis数据库的安装方法与自动启动脚本分享

这篇文章主要介绍了Linux下Redis数据库的安装方法与自动启动脚本分享,自动启动脚本分别针对CentOS和Ubuntu系统来给出了编写示例,需要的朋友可以参考下
收藏 0 赞 0 分享

Ruby与Ruby on Rails框架环境搭建的简明教程

这篇文章主要介绍了Ruby与Ruby on Rails框架环境搭建的简明教程,包括RubyGems的升级与OpenSSL的支持等配置,需要的朋友可以参考下
收藏 0 赞 0 分享

Ruby编写HTML脚本替换小程序的实例分享

这篇文章主要介绍了Ruby编写HTML脚本替换小程序的实例分享,单纯使用Ruby中的字符串替换方法而没有涉及更复杂的正则表达式,需要的朋友可以参考下
收藏 0 赞 0 分享

详解Ruby中的代码块对象Proc

在Ruby中一个代码块block不是对象,但可以用Proc来替代其作为对象进行操作,接下来我们就来详解Ruby中的代码块对象Proc
收藏 0 赞 0 分享

Ruby中的Proc类及Proc的类方法Proc.new的使用解析

用Proc类可以用Proc.new来创建一个Proc类,进而来操作块,这里我们就来进行Ruby中的Proc类及Proc的类方法Proc.new的使用解析.
收藏 0 赞 0 分享
查看更多