将 lambda 作为块传递

Posted

技术标签:

【中文标题】将 lambda 作为块传递【英文标题】:Passing a lambda as a block 【发布时间】:2011-12-31 00:38:39 【问题描述】:

我正在尝试定义一个块,用于传递多个范围的 each 方法。我不想在每个范围内重新定义块,而是创建一个lamba,并像这样传递lambda:

count = 0
procedure = lambda |v| map[count+=1]=v
("A".."K").each procedure
("M".."N").each procedure
("P".."Z").each procedure

但是,我收到以下错误:

ArgumentError:参数数量错误(1 代表 0) 来自 code.rb:23:in `each'

有什么想法吗?

【问题讨论】:

【参考方案1】:

在参数上添加一个 & 符号 (&),例如:

("A".."K").each &procedure

这表示您将它作为方法的特殊块参数传递。否则它被解释为一个正常的参数。

它还反映了您在方法本身中捕获和访问块参数的方式:

# the & here signifies that the special block parameter should be captured
# into the variable `procedure`
def some_func(foo, bar, &procedure)
  procedure.call(foo, bar)
end

some_func(2, 3) |a, b| a * b 
=> 6

【讨论】:

【参考方案2】:

诀窍在于使用&,它告诉Ruby 在必要时将此参数转换为Proc,然后将该对象用作方法的块。从 Ruby 1.9 开始,有一个 lambda(匿名)函数的快捷方式。所以,你可以这样写代码:

(1..5).map &->(x) x*x 
# => [1, 4, 9, 16, 25]

将获取数组的每个元素并计算其幂

和这段代码一样:

func = ->(x)  x*x 
(1..5).map &func

对于 Ruby 1.8:

(1..5).map &lambda |x| x*x
# => [1, 4, 9, 16, 25]

为了解决你的问题,你可以使用Array的方法reduce0是初始值):

('A'..'K').reduce(0)  |sum,elem| sum + elem.size 
# => 11

将 lambda 函数传递给 reduce 有点棘手,但匿名块与 lambda 几乎相同。

('A'..'K').reduce(0)  |sum, elem| ->(sum) sum + 1.call(sum) 
# => 11

或者你可以像这样连接字母:

('A'..'K').reduce(:+)
=> "ABCDEFGHIJK"

转换为小写:

('A'..'K').map &->(a) a.downcase 
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]

在方法定义的上下文中,在最后一个参数前面放置一个 & 符号表示方法可以采用一个块,并为我们提供一个名称来引用方法体中的这个块。

【讨论】:

【参考方案3】:

其他答案留下了一些我想扩展的未澄清内容。我们如何将 arg 和 block 传递给方法?

假设我们有一个方法接受一个 arg 和一个块:

def method_with_arg_and_block(arg)
  puts arg
  yield
end

和一个过程:

pr = proc  puts 'This is a proc'

答案:重要的是您将 proc 作为带有 & 符号的 arg 传递,而不是将 proc 附加到方法中(就像使用块一样)。

例如,如果你这样做:

method_with_arg_and_block('my arg') &pr

你会得到一个“no block given (yield)”异常。

正确的称呼是:

method_with_arg_and_block('my arg', &pr)

Ruby 会负责将 proc 转换为块并将其附加到您的方法中。注意:由于 lambdas 也是 procs,所以这也适用于 lambdas。

感谢https://medium.com/@sihui/proc-code-block-conversion-and-ampersand-in-ruby-35cf524eef55 帮助我理解这一点。

【讨论】:

以上是关于将 lambda 作为块传递的主要内容,如果未能解决你的问题,请参考以下文章

为啥要将一个类作为 lambda 传递?

C# 将 Lambda 表达式作为方法参数传递

将 lambda 作为模板函数参数传递

Lambda

我不能将 lambda 作为 std::function 传递

将Lambda表达式作为参数传递并解析-在构造函数参数列表中使用Lambda表达式