将lambda作为一个块传递

hen*_*lle 58 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
Run Code Online (Sandbox Code Playgroud)

但是,我收到以下错误:

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

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

num*_*407 72

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

("A".."K").each &procedure
Run Code Online (Sandbox Code Playgroud)

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

它还反映了它们捕获和访问方法本身内部的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
Run Code Online (Sandbox Code Playgroud)


Tom*_*art 21

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

(1..5).map &->(x){ x*x }
# => [1, 4, 9, 16, 25]
Run Code Online (Sandbox Code Playgroud)

将获取阵列的每个元素并计算其功率

它与此代码相同:

func = ->(x) { x*x }
(1..5).map &func
Run Code Online (Sandbox Code Playgroud)

对于Ruby 1.8:

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

要解决您的问题,您可以使用Array的方法reduce(0是初始值):

('A'..'K').reduce(0) { |sum,elem| sum + elem.size }
# => 11
Run Code Online (Sandbox Code Playgroud)

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

('A'..'K').reduce(0) { |sum, elem| ->(sum){ sum + 1}.call(sum) }
# => 11
Run Code Online (Sandbox Code Playgroud)

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

('A'..'K').reduce(:+)
=> "ABCDEFGHIJK"
Run Code Online (Sandbox Code Playgroud)

转换为小写:

('A'..'K').map &->(a){ a.downcase }
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
Run Code Online (Sandbox Code Playgroud)

在方法定义的上下文中,将一个&符号放在最后一个参数的前面表示一个方法可以采用一个块并给出一个名称来引用方法体内的这个块.


小智 5

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

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

def method_with_arg_and_block(arg)
  puts arg
  yield
end
Run Code Online (Sandbox Code Playgroud)

和一个过程:

pr = proc { puts 'This is a proc'}
Run Code Online (Sandbox Code Playgroud)

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

例如,如果你这样做:

method_with_arg_and_block('my arg') &pr
Run Code Online (Sandbox Code Playgroud)

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

正确的调用方式是:

method_with_arg_and_block('my arg', &pr)
Run Code Online (Sandbox Code Playgroud)

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

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