Ruby闭包:如何将args和block作为单个参数返回以传递给方法

假设我有一个采用args和块的方法:

def yield_if_widget(*args, &block)
  if args[0].is_a?(Widget)
    block.call
  end
end

我可以使用参数和块来调用此方法:

yield_if_widget(Widget.new) do
  puts "I like widgets"
end

但是如果我有另一个方法来准备参数和块呢?

def widget_and_block
  args = [Widget.new]
  block = proc{ puts "I like widgets" }

  [args, block]
end

我希望能够将它直接传递给第一个方法:

yield_if_widget(*widget_and_block)

这可能吗?怎么样?假设yield_if_widget是在库中定义的并且猴子修补它不是一个选项.

最佳答案 为了让ruby明白方法调用中的参数是一个块,一个商业广告,必须放在它前面.

def widget_and_block
  args = [Widget.new]
  block = proc{ puts "I like widgets" }
  [args, block]
end

wab = widget_and_block
#                           ⇓
yield_if_widget(*wab.first, &wab.last)

Oneliner(它不会返回yiw返回的内容):

widget_and_block.tap { |args, cb| yield_if_widget *args, &cb }

UPD基本上,方法调用中的&符号用于表示“嘿,将其转换为proc并将其用作代码块”到ruby.它是语言的语法部分,就像你必须将数组内容放在方括号内,而不是卷曲.这就是为什么源代码中应该存在&符号的原因.

另一方面,您是否可以自由修改yield_if_widget并从参数列表中删除&符号:

-def yield_if_widget(*args, &block)
+def yield_if_widget(*args, block)

代码将按预期工作,因为proc实例作为最后一个参数传递,并且很自然地允许调用它.

还请注意,将&符号添加到方法调用的最后一个参数强制在其上调用#to_proc方法,如:

[1,2,3].reduce &:+
#⇒ 6

上面的魔法是有效的,因为Symbol类有它自己的#to_proc方法实现.

点赞