假设我有一个这样的类:
class Test
def test_func
140
end
end
Run Code Online (Sandbox Code Playgroud)
和一个proc,它引用了一个成员函数Test:
p = ->(x, y) { x + y + test_func } # => #<Proc:0x007fb3143e7f78@(pry):6 (lambda)>
Run Code Online (Sandbox Code Playgroud)
要调用p,我将它绑定到以下实例Test:
test = Test.new # => #<Test:0x007fb3143c5a68>
test.instance_exec(1, 2, &p) # => 143
Run Code Online (Sandbox Code Playgroud)
现在假设我想传递y给 p,并且总是传递x = 1:
curried = p.curry[1] # => #<Proc:0x007fb3142be070 (lambda)>
Run Code Online (Sandbox Code Playgroud)
理想情况下,我应该instance_exec像以前一样,但相反:
test.instance_exec(2, &curried)
=> NameError: undefined local variable or method `test_func' for main:Object
Run Code Online (Sandbox Code Playgroud)
proc在似乎不正确的绑定中运行.是什么赋予了?
是的,我相信这是一个错误。
我认为这归结为curry返回“C 级过程”而不是正常过程的事实。我不完全理解两者之间的区别(我猜前者是由 Ruby C 代码创建的,这就是curry它的作用),但是当您尝试进行绑定时,您可以看出它们是不同的。
p.binding # => #<Binding:0x000000020b4238>
curried.binding # => ArgumentError: Can't create a binding from C level Proc
Run Code Online (Sandbox Code Playgroud)
通过查看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);
}
Run Code Online (Sandbox Code Playgroud)
我错过的分支 ( ...) 最终vm_push_frame以看起来像一些环境的方式调用,而vm_yield_with_cfunc实际上却没有。
所以我的猜测是,因为 curried proc 是在 C 代码中创建的,并且最终具有与您的第一个 proc 不同的“类型”,所以在上面的代码段中采用了另一个分支,并且没有使用环境。
我要指出的是,这一切是相当投机基于阅读的代码,我没有运行任何测试或尝试新鲜事物出来(我也不会全部是熟悉内部红宝石反正!)
| 归档时间: |
|
| 查看次数: |
142 次 |
| 最近记录: |