【问题标题】:Ruby Block Scope with instance_eval带有 instance_eval 的 Ruby 块作用域
【发布时间】:2015-06-27 16:01:56
【问题描述】:

我对 Ruby 块和 proc 的理解是它们都是闭包。现在我已经看到它与 instance_eval 一起使用,我有点困惑。与使用 instance_eval 相比,什么是神奇的酱料,即查看裸机时的底层工作原理,它改变了块的范围在最常见的用途下的行为方式?

这是一个示例,您可以在 IRB 中转储以了解我的意思。我已经包含了 proc.call 和 block yield 版本示例。令人高兴的是,它们的行为方式相同。

# Testing block/proc and eval
class Example
  def initialize(value)
    # value defined in the instance
    @value = value
  end

  def call_a_proc(proc)
    proc.call self
  end

  def yield_to_block
    yield self
  end
end

# Value defined in the global object
@value = 1
example = Example.new 'a'

# the block/proc that prints @value
proc1 = -> instance { puts @value }

# instance calling/yielding the block/proc that prints @value
proc2 = -> instance { instance.call_a_proc proc1 }
proc3 = -> instance { instance.yield_to_block &proc1 }

# instance_eval of the block that prints @value
proc4 = -> instance { instance.instance_eval &proc1 }

# the block/proc reference @value from the global context, the context in which it was defined (standard closure)
example.call_a_proc proc1
example.yield_to_block &proc1
example.call_a_proc proc2
example.yield_to_block &proc2
example.call_a_proc proc3
example.yield_to_block &proc3

# block/proc has it's context redefined as coming from within the instance.
example.call_a_proc proc4
example.yield_to_block &proc4

我知道这就是 instance_eval 方法的重点,我只是不确定它是如何工作的。

【问题讨论】:

    标签: ruby scope block proc instance-eval


    【解决方案1】:

    当您在词法范围(您的主源文件)中定义@value 时,您正在全局解释器中定义一个实例变量。例如:

    self #=> main
    # "self" here refers to the main interpreter, which is of class Object
    self.instance_variable_get(:@value) #=> 1
    # "example" is your instance above
    example.instance_variable_get(:@value) #=> "a"
    # "self" has been changed to refer to "example" using instance_eval
    example.instance_eval { self.instance_variable_get(:@value) } #=> "a"
    # this syntax is just a shortcut for the line above
    example.instance_eval { @value } #=> "a"
    

    使用instance_eval,您只需将主解释器self 替换为您调用的对象instance_eval

    【讨论】:

    • 绑定类,完美!当我有空闲的周末时,我会更深入地研究这个魔法,哈哈。谢谢!
    • 不,instance_eval 不会更改块的Binding。实际上恰恰相反:局部变量绑定几乎是它改变的唯一东西。它改变的是self的值。
    • 是的!抱歉错误,感谢您的评论。刚刚再次破解了元编程红宝石书,将更新答案。
    猜你喜欢
    • 1970-01-01
    • 2022-11-13
    • 2012-01-12
    • 2011-03-11
    • 2015-06-25
    • 2013-01-03
    • 2011-05-23
    • 2017-04-22
    • 2016-03-22
    相关资源
    最近更新 更多