簡體   English   中英

可以對instance_eval進行咖喱處理嗎?

[英]Possible to instance_eval a 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 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_cvm.c ,這取決於分支iseq類型:

else if (BUILTIN_TYPE(block->iseq) != T_NODE) {
    ...
} else {
    return vm_yield_with_cfunc(th, block, self, argc, argv, blockptr);
}

我錯過的分支( ... )最終以類似於vm_yield_with_cfunc沒有的環境的方式調用vm_push_frame

因此,我的猜測是,因為咖喱的proc是用C代碼創建的,並且結局的類型與您的第一個proc不同,所以上面的代碼段采用了另一個分支,並且不使用環境。

我要指出的是,這一切是相當投機基於閱讀的代碼,我沒有運行任何測試或嘗試新鮮事物出來(我也沒有那么熟悉內部紅寶石反正!)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM