深入理解 Ruby 中的 instance_eval 和 class_eval

2017-09-06 19:23:37来源:CSDN作者:antony1776人点击

分享

Ruby 通过 eval 可以将字符串当做代码来执行,而执行环境是通过 binding 进行绑定的;除此之外,Ruby 还有另外两个方法:instance_eval 和 class_eval, 用来执行代码块。后者的执行上下文与调用者相关。

instance_eval: 调用者必须是实例 instance;
class_eval: 调用者必须是类 class;

下面的例子帮助识别两个方法的区别:

[1] pry(main)> class Hello[1] pry(main)*   def self.say_c[1] pry(main)*     puts "Hello self.say"[1] pry(main)*   end  [1] pry(main)*   def say_i[1] pry(main)*     puts "Hello lsay"[1] pry(main)*   end  [1] pry(main)* end  

在 pry 交互环境中,先定义一个 Hello 类,有两个方法,一个类方法 say_c, 一个实例方法 say_i。

[2] pry(main)> ls HelloHello.methods: say_cHello#methods: say_i

分别通过 Hello.instance_eval 和 Hello.class_eval 定义两个新方法: foo_i, foo_c

[4] pry(main)> Hello.instance_eval do [4] pry(main)*   def fool_i[4] pry(main)*     puts "Hello instance_eval foo_i"[4] pry(main)*   end  [4] pry(main)* end  => nil[5] pry(main)> Hello.class_eval do[5] pry(main)*   def foo_c[5] pry(main)*     puts "Hello class_eval foo_c"[5] pry(main)*   end  [5] pry(main)* end  => nil

查看 Hello 的方法变化:

[6] pry(main)> ls HelloHello.methods: foo_i  say_cHello#methods: foo_c  say_i

有上面的结果可见,instance_eval 代码块中定义的方法变成了 Hello 的类方法,而 class_eval 代码块中
定义的方法称为了 Hello 类的实例方法。这里有点绕,跟语义上边理解起来的相反。

[7] pry(main)> h1 = Hello.new=> #<Hello:0x007ff978fc5458>[8] pry(main)> h1.instance_eval do [8] pry(main)*   def cry[8] pry(main)*     puts "h1 cry"[8] pry(main)*   end  [8] pry(main)* end  => nil[9] pry(main)> ls h1Hello#methods: foo_c  say_iself.methods: cry

h1 为 Hello 类的实例,h1.instance_eval 中定义的方法成为了 h1 的单例方法(类似于java中类的静态方法),也就是说只有 h1 能够调用的方法。

总结:

  • h1 不能调用 class_eval;
  • h1 调用 instance_eval 的作用域为对象实例本身;其中定义的方法为单例方法;
  • Hello 调用 class_eval 的作用域为类本身;其中定义的方法为实例方法;
  • Hello 调用 instance_eval 的作用域为 class 对象,其中定义的方法为类方法;

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台