Ruby中为何无法获取块的上下文(Proc)?技术求助
问题:无法获取块(Proc)的上下文原因分析
现有代码实现
MyBuilder类(用于存储Proc)
class MyBuilder attr_reader :values def initialize(something) @something = something @values = {} end def inner(name, &block) @values[name] = block end end
Out类(使用instance_exec处理块)
require './my_builder' class Out def self.outer(sth, builder, &block) builder.instance_exec(&block) p "result", builder.values end end
正常工作的测试场景
此场景能正确得到结果:oneone:
Out.outer(:hello, builder) do builder.inner(:one) { :oneone } end
无法正常工作的场景
尝试捕获do event :assign do ...这个块时失败:
# datan status: {unassigned: 0, assigned: 1, resolved: 2} do # event :assign do # transition :unassigned => :assigned # end # end def self.datan(name = nil, values = nil, **options, &block) # options is {unassigned: 0, assigned: 1, resolved: 2} # block should `do event :assign do ...` Out.outer(:hello, builder) do builder.inner(:one) { block } end end
问题原因及解决方案
核心原因
你当前写法的问题在于:builder.inner(:one) { block }只是把block这个Proc对象本身放进新块里存储,既没有执行原block的逻辑,也没正确绑定原block的上下文。后续调用存储的块时,得到的只是原Proc对象,而非它执行后的结果,甚至可能因为作用域问题导致原Proc无法正确运行。
修正方案
方案1:直接传递原block给inner方法
不需要包裹新块,直接把原block作为参数传递给inner,就能正确保存原Proc及其上下文:
Out.outer(:hello, builder) do builder.inner(:one, &block) end
方案2:需要额外逻辑时显式调用原block
如果要在保存的块里添加自定义逻辑,可在新块中用instance_exec显式调用原block,确保上下文正确绑定:
Out.outer(:hello, builder) do builder.inner(:one) do # 这里可以添加自定义逻辑 instance_exec(&block) end end
补充说明
你在Out.outer中用builder.instance_exec(&block)是把块的上下文绑定到builder实例,但之前的错误写法里,传递给outer的块只是把原block变量存起来,完全没处理它的上下文绑定,自然无法正确获取原块的执行结果和上下文。
内容的提问来源于stack exchange,提问作者Snny Pictures
相关产品推荐
相关产品推荐

