gpt4 book ai didi

ruby - Proc.new 如何找到这段代码中的 block ?

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

我有以下代码:

def call_block
Proc.new.call
my_local_proc = Proc.new { Proc.new.call }
my_local_proc.call
end

call_block { p 'block' }

输出是:

block
block

有人可以向我解释 Proc.new 如何找到我传递给 call_block 的 block 吗?我猜 Proc.new 只是搜索最近的 block ,并且它完全是用 C++ 实现的。

我还有一个问题:仅使用 ruby​​ 可以实现这样的功能吗?我是说,我可以编写一个方法,如果没有给出 block ,则获取传递给调用它的方法的 block 。像这样的东西:

def bar
if not block_given?
#use the block that has been given to the caller
end
# some code
end

def foo
bar
end

foo { :block }

最佳答案

Proc.new 将使用该方法的 block ,如果在没有附加一个的方法中调用的话。 This is documented behavior .

要了解 YARV 是如何做到的,让我们阅读源代码。具体来说,proc_new function :

block_pointer = rb_vm_control_frame_block_ptr(control_frame_pointer);

此行检索指向与当前控制帧关联的 block 的指针。

我相信这些控制框架实现了 Ruby 的堆栈。我们目前在 Proc.new 控制框架内,因此这将检索指向给定方法的 block 的指针。

if (block_pointer != NULL) {
/* block found */
} else {
/* block not found... */
}

如果指针不是NULL,则Proc.new 被显式传递给一个 block 。但是,如果指针 NULL 怎么办?

/* block not found... */
control_frame_pointer = RUBY_VM_PREVIOUS_CONTROL_FRAME(control_frame_pointer);
block_pointer = rb_vm_control_frame_block_ptr(control_frame_pointer);

我们在堆栈上向上移动并尝试获取它的 block 。换句话说,我们向上移动到调用者的控制框架并尝试获取它的 block 。

if (block_pointer != NULL) {
if (is_lambda) {
rb_warn("tried to create Proc object without a block");
}
} else {
rb_raise(rb_eArgError, "tried to create Proc object without a block");
}

现在,如果它不是NULL,那么我们就基本成功了。如果它仍然 NULL,那么我们就不能创建一个Proc,所以我们提出一个ArgumentError

算法归结为:

  1. 查看 Proc.new 是否被分配了一个 block
    1. 如果是,使用它
    2. 如果没有,查看是否给调用者一个 block
      1. 如果是,使用它
      2. 如果不是,报错

为便于阅读修改了源代码。访问 GitHub 上的链接源文件以获取原始文件。

关于ruby - Proc.new 如何找到这段代码中的 block ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13672174/

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