詳解Ruby中的instance_eval方法及其與class_eval的對(duì)比
instance_eval方法
這個(gè)BasicObject#instance_eval有點(diǎn)類似JS中的bind方法,不同的時(shí),bind是將this傳入到對(duì)象中,而instance_eval則是將代碼塊(上下文探針Context Probe)傳入到指定的對(duì)象中,一個(gè)是傳對(duì)象,一個(gè)是傳執(zhí)行體。通過這種方式就可以在instance_eval中的代碼塊里訪問到調(diào)用者對(duì)象中的變量。
示例代碼
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方法還有一個(gè)雙胞胎兄弟:instance_exec方法。相比前者后者更加靈活,允許對(duì)代碼塊傳入?yún)?shù)。
示例代碼
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”
因?yàn)檎{(diào)用instance_eval后,將調(diào)用者作為了當(dāng)前的self,所以作用域更換到了class C中,之前的作用域就不生效了。這時(shí)如果還想訪問到之前@y變量,就需要通過參數(shù)打包上@y一起隨instance_eval轉(zhuǎn)義,但因?yàn)閕nstance_eval不能攜帶參數(shù),所以使用其同胞兄弟instance_exec方法。
instance_eval 與 class_eval 的區(qū)別
###instance_eval
首先從名字可以得到的信息是,instance_eval的調(diào)用者receiver必須是一個(gè)實(shí)例instance,而在instance_eval block的內(nèi)部,self即為receiver實(shí)例本身。
obj_instance.instance_eval do self # => obj_instance # current class => obj_instance's singleton class end <!--more-->
根據(jù)這個(gè)定義,如果在一個(gè)實(shí)例上調(diào)用了instance_eval,就可以在其中定義該實(shí)例的單態(tài)函數(shù) 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>
同樣,因?yàn)轭恈lass本身也是Class類的一個(gè)實(shí)例,instance_eval也可以用在類上,這個(gè)時(shí)候就可以在其中定義該類的singleton_method,即為該類的類函數(shù)。
換句話說,可以用instance_eval來定義類函數(shù)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的調(diào)用者receiver必須是一個(gè)類,而在class_eval block的內(nèi)部,self即為receiver類本身。
class A end A.class_eval do self # => A # current class => A end
根據(jù)這個(gè)定義,如果在一個(gè)類上調(diào)用了class_eval,就可以在其中定義該類的實(shí)例函數(shù) 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來定義實(shí)例函數(shù)instance method,這也比較容易混淆,需要搞清楚。
相關(guān)文章
Ruby程序中發(fā)送基于HTTP協(xié)議的請求的簡單示例
這篇文章主要介紹了Ruby程序中發(fā)送基于HTTP協(xié)議的請求的簡單示例,包括對(duì)HTTPS請求的介紹,需要的朋友可以參考下2016-03-03
Ruby實(shí)現(xiàn)命令行中查看函數(shù)源碼的方法
這篇文章主要介紹了Ruby實(shí)現(xiàn)命令行中查看函數(shù)源碼的方法,,需要的朋友可以參考下2014-07-07
詳解Ruby中的instance_eval方法及其與class_eval的對(duì)比
Ruby的eval族方法將字符串作為代碼來執(zhí)行,instance_eval方法便是其中之一,下面就來詳解Ruby中的instance_eval方法及其與class_eval的對(duì)比2016-05-05
設(shè)計(jì)模式中的觀察者模式在Ruby編程中的運(yùn)用實(shí)例解析
這篇文章主要介紹了設(shè)計(jì)模式中的觀察者模式在Ruby編程中的運(yùn)用實(shí)例解析,觀察者模式中主張?jiān)O(shè)立觀察者對(duì)象來降低對(duì)象之間的耦合,需要的朋友可以參考下2016-04-04
Ruby配置rspec和RestClient來檢測服務(wù)器
這篇文章主要介紹了Ruby配置rspec和RestClient來檢測服務(wù)器的方法,包括JSON文件的相關(guān)配置,需要的朋友可以參考下2015-07-07

