instance_eval方法
這個BasicObject#instance_eval有點類似JS中的bind方法,不同的時,bind是將this傳入到對象中,而instance_eval則是將代碼塊(上下文探針Context Probe)傳入到指定的對象中,一個是傳對象,一個是傳執(zhí)行體。通過這種方式就可以在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 的區(qū)別
###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,就可以在其中定義該實例的單態(tài)函數 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字符串、條件、循環(huán)、數組、Hash、類基本操作筆記