3

我正在尝试一些 ruby​​ 元编程,但对 instance_eval() 感到有些困惑。

见下面的例子

@instance_var = 'instance_var'
local_var = 'local_var'
obj = Object.new
obj.instance_eval { p @instance_var; p local_var }
obj.instance_eval { @instance_var  = 'instance_var_in_obj'; local_var = 'local_var_in_obj' }
p @instance_var; p local_var

我希望@instance_var 和 local_var 都可以在块中传递/修改,但我得到了

nil
"local_var"
"instance_var"
"local_var_in_obj"

结果我们可以共享(通过/修改)本地变量,instance_val但实例变量属于self不能共享。

关于instance_exec

obj.instance_exec(@instance_var) {|instance_var| p instance_var; instance_var = @instance_var }
=> "instance_var"
@instance_var
=> "instance_var"

现在我可以传递我的外部实例 var 并且仍然不能修改它。

@instance_arr = []
obj.instance_exec(@instance_arr) {|instance_arr| instance_arr << 'in_block' }
@instance_arr
=> ["in_block"]
obj.instance_exec(@instance_arr) {|instance_arr| instance_arr = [] }
@instance_arr
=> ["in_block"]

使用数组的实例变量,我可以修改我的实例变量,但只能在当前数组对象中

总而言之,instance_eval还是instance_exec使用本地变量而不是实例变量?

我错过了一些概念吗?

4

2 回答 2

1

经过我朋友的一些搜索和建议,我想我找到了问题所在。Context在 ruby​​ 中,当您的代码运行时self有两个binding,当您使用local varsmethod不使用 set时,self.xxx首先检查它是否在您的binding对象中,因为local var如果不是,Ruby 会认为它是一种方法,然后搜索您的self对象以找到它的定义并调用它. 这么想:

class A
  def test
    4
  end
  def use_variable
    test = 5
    test
  end
  def use_method
    test = 5
    self.test
  end
end
a = A.new
a.use_variable # returns 5
a.use_method   # returns 4

这是解释WHY的,instance_eval因为它的文档说instance_eval刚刚self在给定的块中发生了变化,而不是触摸binding,所以方法将在新的self、本地的 val 上搜索仍然在同一个binding对象中。

关于instance_exec我不太确定这一点,但似乎实例 vars(带有前缀 vars)它将self直接在跳过上搜索binding,所以在instance_exec@instance_arr属于旧的selfinstance_exec块中,你local var在新binding的块中将它作为新的(块有自己的范围)但它的值实际上是@instance_arr新的调用方法的引用,local var比如push它会改变它们,因为它们共享相同Array instance,但是当你将一个新Array instance的分配给新的时,local var它们不再是相同的Array instance那是第二个WHY

于 2015-04-19T08:01:20.043 回答
0

为了评估局部变量,您需要传入字符串“local_var”,它将返回局部变量的值。根据我对文档的解释,如果您传入一个块,则无法传入参数。

块形式的实例 eval 的行为是将调用所在对象的实例变量和私有方法作为闭包访问。

带有参数的实例 eval 的行为允许您在该调用范围内评估字符串。

于 2015-04-13T09:29:56.547 回答