假设我有一个这样的类:
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在似乎不正确的绑定中运行。是什么给了什么?
答案 0 :(得分:4)
是的,我相信这是一个错误。
我认为归结为curry
返回“C级别proc”而非正常proc的事实。我不完全理解两者之间的区别(我猜测前者是由Ruby C代码创建的,这是curry
所做的),但你可以告诉他们在你尝试采取时有所不同一个约束力。
p.binding # => #<Binding:0x000000020b4238>
curried.binding # => ArgumentError: Can't create a binding from C level Proc
通过查看the source,看起来它们的内部结构表示对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
看起来像{{1}}那样的环境。
所以我的猜测是因为curry proc是用C代码创建的,结果是与你的第一个proc不同的'type',另一个分支被带到上面的代码片段中并且没有使用环境。
我应该指出,所有这些都是基于阅读代码的相当推测,我没有运行任何测试或尝试任何东西(我也不是所有熟悉内部无论如何,Ruby!)