instance_eval中的ruby访问实例变量

时间:2015-04-13 05:50:17

标签: ruby metaprogramming instance-variables instance-eval

我正在尝试一些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"]

使用数组的实例var我可以修改我的实例var但仅限于当前数组对象

摘要播放instance_evalinstance_exec本地变量而不是实例变量?

我错过了一些概念吗?

2 个答案:

答案 0 :(得分:1)

经过我的朋友的一些搜索和建议,我想我发现了问题。 在ruby中,当您的代码运行Contextself时,当您使用bindinglocal vars而没有设置method时,有两个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的{​​{1}}因为其文档instance_eval刚刚在给定的块中更改了instance_eval而未触及self因此将搜索方法新的binding,本地值仍然在同一个self对象中。

关于binding我对此并不十分肯定,但似乎是实例变量(在vars前缀),它将在instance_exec上搜索直接跳过self,因此binding您的instance_exec属于旧版@instance_arrself阻止您将其作为新instance_exec块中的local var块(块具有自己的范围)但它的值实际上是binding的引用,因此在新的@instance_arr上调用方法,例如local var,它将改变它们两者,因为它们共享相同{{1}但是,当您为新的push分配新的Array instance时,他们不再引用与Array instance相同的local var

答案 1 :(得分:0)

为了评估局部变量,你需要传入字符串`&#34; local_var&#34;它将返回局部变量的值。根据我对the documentation的解释,如果传入一个块,则无法传入参数。

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

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