简体   繁体   English

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

[英]Ruby Closures: How to return args and block as a single argument to pass to a method

Suppose I have a method that takes args and a block: 假设我有一个采用args和块的方法:

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

I can call this method with arguments and a block: 我可以使用参数和块来调用此方法:

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

But what if I have another method that prepares the arguments and the block: 但是如果我有另一个方法来准备参数和块呢?

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

  [args, block]
end

And I want to be able to pass it directly to the first method: 我希望能够将它直接传递给第一个方法:

yield_if_widget(*widget_and_block)

Is this possible? 这可能吗? How? 怎么样? Assume that yield_if_widget is defined in a library and monkey-patching it is not an option. 假设yield_if_widget是在库中定义的并且猴子修补它不是一个选项。

To make ruby understand that the parameter in a call to a method is a block, a commercial and must be put in front of it. 为了让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 (it won't return what yiw returns): Oneliner(它不会返回yiw返回的内容):

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

UPD Basically, ampersand in method call is used to say “hey, convert this to proc and use as codeblock” to ruby. UPD基本上,方法调用中的&符号用于表示“嘿,将其转换为proc并将其用作代码块”到ruby。 It's a syntax part of the language, like you have to put array content inside square brackets, not curly. 它是语言的语法部分,就像你必须将数组内容放在方括号内,而不是卷曲。 That's why an ampersand should exist in the source code. 这就是为什么源代码中应该存在&符号的原因。

On the other hand, whether you were free to modify the yield_if_widget and remove ampersand from parameter list: 另一方面,您是否可以自由修改yield_if_widget 从参数列表中删除&符号

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

the code would work as expected, since the proc instance is passed as the last parameter and calling call method on it is very naturally permitted. 代码将按预期工作,因为proc实例作为最后一个参数传递,并且很自然地允许call它。

Please also note, that prepending an ampersand to the last parameter to method call forces #to_proc method to be called on it, like in: 还请注意,将&符号添加到方法调用的最后一个参数强制在其上调用#to_proc方法,如:

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

The magic above works because Symbol class has it's own implementation of #to_proc method. 上面的魔法是有效的,因为Symbol类有它自己的#to_proc方法实现。

you can't do it in one line (as far as I can tell). 你不能一行(据我所知)。 You need temporary variables. 你需要临时变量。

given these methods: 给出这些方法:

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

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

You can pass the return values from prepare to your method like so: 您可以将prepare的返回值传递给您的方法,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM