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

标签 ruby search find block proc

我有以下代码:

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 ,则将使用该方法的 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. 如果没有,查看调用者是否被阻止
      1. 如果是这样,请使用它
      2. 如果没有,则引发错误

为了可读性而修改了源代码。访问 GitHub 上的链接源文件以获取原始文件。

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

相关文章:

c++ - 如何使用std::find查找具有struct成员值的set元素?

python - 在列表中搜索字符或字符串(如网站上的查找功能)

fragment 中的 Android 搜索建议

ruby - 在实例化时将类转换为子类

ruby - 是否可以使用 watir 在浏览器中导航回来?

ruby - Vagrant 默认使用 Ruby 1.9.3

php - Eclipse 搜索结果 - 文件名未显示

python - 如何在字符串中搜索单词(完全匹配)?

mongodb 找到一个很严格的文档

ruby - 我如何在 Clojure 中编写 Ruby 的 each_cons?