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

时间:2015-05-08 14:30:53

标签: ruby closures

假设我有一个采用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在库中定义并且猴子修补它不是一个选项。

2 个答案:

答案 0 :(得分:2)

为了让ruby明白方法调用中的参数是一个块, commercial和必须放在它前面。

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实例作为最后一个参数传递,并且非常自然地允许在其上调用call方法。

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

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

上面的魔术有效,因为Symbol类有自己的#to_proc方法实现。

答案 1 :(得分:0)

你不能在一行中做到(据我所知)。你需要临时变量。

给出这些方法:

def prepare
  return [4, proc { puts "called" }]
end

def run(a, &block)
  puts a
  block.call
end

您可以将prepare的返回值传递给您的方法,如下所示:

i,blk = prepare()
run(i, &blk)