ruby – 可能instance_eval一个curried proc?

假设我有一个这样的类:
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级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时这很重要,它最终在vm.c调用invoke_block_from_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没有.

所以我的猜测是因为curried的proc是用C代码创建的,并且结果与你的第一个proc不同,所以另一个分支是在上面的代码片段中使用的,并且不使用环境.

我应该指出,所有这些都是基于阅读代码的非常推测,我没有运行任何测试或尝试过任何东西(而且我也不是那么熟悉内部Ruby!)

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...