将lambda作为一个块传递

时间:2011-11-17 04:48:03

标签: ruby lambda

我正在尝试定义一个块,我将用它来传递多个范围的每个方法。我不想在每个范围上重新定义块,而是想创建一个lamba,然后传递lambda:

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

但是,我收到以下错误:

ArgumentError: wrong number of arguments(1 for 0)
    from code.rb:23:in `each'

有什么想法在这里发生了什么?

3 个答案:

答案 0 :(得分:68)

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

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

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

它还反映了你捕获和访问方法本身内部的block参数的方式:

# 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

答案 1 :(得分:20)

诀窍在于使用&告诉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

for Ruby 1.8:

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

要解决您的问题,您可以使用数组的方法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"]

在方法定义的上下文中,将一个&符号放在最后一个参数的前面表示一个方法可能会占用一个块并给我们一个名称来引用方法体内的这个块。

答案 2 :(得分:1)

其他答案未阐明,我想继续讨论。我们如何将arg和块传递给方法?

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

def method_with_arg_and_block(arg)
  puts arg
  yield
end

和proc

pr = proc { puts 'This is a proc'}

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

例如,如果您这样做:

method_with_arg_and_block('my arg') &pr

您将获得“未提供任何块(产量)”异常。

正确的调用方式是:

method_with_arg_and_block('my arg', &pr)

Ruby将负责将proc转换为块并将其附加到您的方法中。注意:由于lambda也是proc,因此也适用于lambda。

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