首页 > 解决方案 > Ruby 方法可以访问隐式块参数吗?

问题描述

传递给 Ruby 方法的隐式块参数可以使用 来执行yield,或者可以使用 来检查它的存在block_given?。我正在尝试将此隐式块传递给另一个方法。

这可能吗?

(它可以访问我要询问的隐式块参数。用显式参数替换它不会削减它。)

标签: rubyclosuresblock

解决方案


您可以 procify 它,更重要的是给它一个名称,以便您可以引用它,使用&方法的参数列表中的 & 符号一元前缀 sigil,如下所示:

#implicit, anonymous, cannot be referenced:
def foo
  yield 23 if block_given?
end

foo {|i| puts i }
# 23

#explicit, named, can be referenced:
def bar(&blk)
  yield 23 if block_given? # still works

  blk.(42) if blk # but now it also has a name and is a `Proc`

  # since we have the block available as an object, we can inspect it
  p blk.arity, blk.parameters, blk.source_location, blk.binding

  b = blk.binding
  p b.local_variables.map {|var| [var, b.local_variable_get(var)] }.to_h
end

quux = "Hello"

bar { |a, b, c = nil, d: nil, &e| puts a }
# 23
# 42
# 2
# [[:opt, :a], [:opt, :b], [:opt, :c], [:key, :d], [:block, :e]]
# ["(irb)", 24]
# #<Binding:0x00007fb091051308>
# { :quux => "Hello" }

这是你的两个选择:

  • 隐式的,匿名的,不是一个对象
  • 明确的,命名的,Proc

Proc::new曾经有一个未记录的技巧,实际上是在 MRI 中实现的一个意想不到的副作用:Proc::new没有检查您是否通过了一个块,它只是假设您通过了一个块并将第一个块从顶部移开内部虚拟机堆栈。因此,如果您没有将块传递给Proc::new,它实际上最终会Proc为传递给该方法的隐式块创建一个(因为它恰好位于堆栈顶部)。

但是,这永远不能移植,永远不能保证,永远不会在所有 Ruby 实现中工作,并且 AFAIK 不再在 YARV 中工作。


推荐阅读