gpt4 book ai didi

ruby - 传递给 `instance_exec` 时如何执行 proc

转载 作者:数据小太阳 更新时间:2023-10-29 06:50:44 27 4
gpt4 key购买 nike

问题的灵感来自 this one .

Proc::new 有一个选项可以在方法内部没有 block 的情况下调用:

Proc::new may be called without a block only within a method with an attached block, in which case that block is converted to the Proc object.

proc/lambda 实例作为代码块传递时,将创建 Proc 的新实例:

Proc.singleton_class.prepend(Module.new do
def new(*args, &cb)
puts "PROC #{[block_given?, cb, *args].inspect}"
super
end
end)

Proc.prepend(Module.new do
def initialize(*args, &cb)
puts "INIT #{[block_given?, cb, *args].inspect}"
super
end
def call(*args, &cb)
puts "CALL #{[block_given?, cb, *args].inspect}"
super
end
end)

λ = ->(*args) { }
[1].each &λ
#⇒ [1]

正如人们可能看到的,对 Proc::new 的调用都没有发生,Proc#initialize 和/或 Proc#call 也没有发生打电话。

问题是:ruby 如何在幕后创建和执行 block 包装器?


NB 不要在 pry/irb 控制台中测试上面的代码:他们知道纯粹执行此代码会出现故障,基本上因为他们修补了过程。

最佳答案

在 Ruby Issue Tracker 上已经对这种行为进行了一些讨论,请参阅 Feature #10499: Eliminate implicit magic in Proc.new and Kernel#proc .

这是 YARV 的一个实现工件:YARV 将一个 block 压入全局 VM 堆栈,而 Proc::new 只是从最顶层的 block 创建一个 Proc堆。所以,如果你碰巧从一个用 block 调用的方法中调用 Proc.new,它会很高兴地捕获堆栈顶部的任何 block ,而不会检查它来自哪里。不知何故,在某个地方,在时间的迷雾中,这个(让我们称之为)“意外工件”(我实际上更愿意称之为错误)成为了一个记录的功能。 JRuby(可能还有 Rubinius、Opal、MagLev 等)的开发人员宁愿摆脱这一功能。

由于大多数其他实现的工作方式完全不同,这种在 YARV 上“免费”出现的行为使得 block 和 Proc::new 在其他实现上的成本更高,并且禁止可能的优化(这不会在 YARV 上受到伤害,因为 YARV 没有优化)。

关于ruby - 传递给 `instance_exec` 时如何执行 proc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40739398/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com