假设我有一个这样的类:
class Test
def test_func
140
end
end
还有一个proc,它引用来自的成员函数Test
:
p = ->(x, y) { x + y + test_func } # => #<Proc:0x007fb3143e7f78@(pry):6 (lambda)>
要调用p
,我将其绑定到以下实例Test
:
test = Test.new # => #<Test:0x007fb3143c5a68>
test.instance_exec(1, 2, &p) # => 143
现在,假设我只想传递y
给p
,并且始终传递x = 1
:
curried = p.curry[1] # => #<Proc:0x007fb3142be070 (lambda)>
理想情况下,我应该能够instance_exec
像以前一样,但是:
test.instance_exec(2, &curried)
=> NameError: undefined local variable or method `test_func' for main:Object
proc运行在似乎是不正确的绑定中。是什么赋予了?
是的,我相信这是一个错误。
我认为可以归结为curry
返回“ C level proc”而不是正常proc的事实。我还不完全了解两者之间的区别(我猜前者是由Ruby C代码创建的,而后者curry
确实是这样做的),但是当您尝试进行绑定时,您可以告诉他们它们是不同的。
p.binding # => #<Binding:0x000000020b4238>
curried.binding # => ArgumentError: Can't create a binding from C level Proc
通过查看源代码,看起来它们的内部结构表示形式对该iseq
成员具有不同的值,该值表示此块保留什么样的指令序列。
当您调用时instance_exec
,这很重要,它最终最终invoke_block_from_c
在vm.c中进行调用,该调用根据iseq
类型而分支:
else if (BUILTIN_TYPE(block->iseq) != T_NODE) {
...
} else {
return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr);
}
我错过的分支(...
)最终vm_push_frame
以看起来像某个环境的调用,而vm_yield_with_cfunc
没有。
因此,我的猜测是,因为咖喱的proc是用C代码创建的,并且结局的类型与您的第一个proc不同,所以上面的代码段采用了另一个分支,并且不使用环境。
我要指出的是,这一切是相当投机基于阅读的代码,我没有运行任何测试或尝试新鲜事物出来(我也不会全部是熟悉内部红宝石反正!)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句