Ruby:在将proc转换为块时提供参数

我们可以轻松定义一个方法并将其转换为带有一元&符号的块。

def my_method(arg) puts arg*2 end ['foo', 'bar'].each(&method(:my_method)) # foofoo # barbar # or my_method = ->(arg) { puts arg*2 } ['foo', 'bar'].each(&my_method) # same output 

正如我们所看到的,当我们使用聚合时,第一个参数会自动传递。 但是,如果我们需要传递2个甚至更多的参数呢?

 my_method = ->(arg,num) { puts arg*num } ['foo', 'bar'].each(&my_method) # ArgumentError: wrong number of arguments (1 for 2) ['foo', 'bar'].each(&my_method(3)) # NoMethodError: undefined method `foo' for main:Object ['foo','bar'].each do |i, &my_method| yield i, 3 end # LocalJumpError: no block given (yield) 

在将proc转换为块时,是否可以传递其他参数?

关于你的评论 :

奇怪,但它在演出期间交换了论点

实际上,参数顺序保留的。

curry返回一个新的proc,它有效地收集参数,直到有足够的参数来调用原始方法/ proc(基于它的arity)。 这是通过返回中间过程来实现的:

 def foo(a, b, c) { a: a, b: b, c: c } end curried_proc = foo.curry #=> # curried_proc[1] #=> # curried_proc[1][2] #=> # curried_proc[1][2][3] #=> {:a=>1, :b=>2, :c=>3} 

你可以一次将任意数量的参数传递给curried的proc:

 curried_proc[1][2][3] #=> {:a=>1, :b=>2, :c=>3} curried_proc[1, 2][3] #=> {:a=>1, :b=>2, :c=>3} curried_proc[1][2, 3] #=> {:a=>1, :b=>2, :c=>3} curried_proc[1, 2, 3] #=> {:a=>1, :b=>2, :c=>3} 

空参数被忽略:

 curried_proc[1][][2][][3] #=> {:a=>1, :b=>2, :c=>3} 

但是,你显然无法改变参数顺序。


currying的替代方法是部分应用程序 ,它通过修复一个或多个参数来返回具有较低arity的新proc。 与curry不同,没有内置的部分应用方法,但您可以轻松编写自己的方法:

 my_proc = -> (arg, num) { arg * num } def fix_first(proc, arg) -> (*args) { proc[arg, *args] } end fixed_proc = fix_first(my_proc, 'foo') #=> # fixed_proc[2] #=> "foofoo" fixed_proc[3] #=> "foofoofoo" [2, 3].map(&fixed_proc) #=> ["foofoo", "foofoofoo"] 

或修复最后一个参数:

 def fix_last(proc, arg) -> (*args) { proc[*args, arg] } end fixed_proc = fix_last(my_proc, 2) #=> # fixed_proc['foo'] #=> "foofoo" fixed_proc['bar'] #=> "barbar" ['foo', 'bar'].map(&fixed_proc) #=> ["foofoo", "barbar"] 

当然,您不仅限于修复单个参数。 例如,您可以返回一个采用数组并将其转换为参数列表的proc:

 def splat_args(proc) -> (array) { proc[*array] } end splatting_proc = splat_args(my_proc) [['foo', 1], ['bar', 2], ['baz', 3]].map(&splatting_proc) #=> ["foo", "barbar", "bazbazbaz"] 

@sawa是对的。 你可以用curry做到这一点。

Proc版本:

 mult = proc {|a, b| a * b} # => # [1, 2].map(&mult.curry[2]) # => [2, 4] 

方法版本:

 def mult(a, b) a*b end [1, 2].map(&method(:mult).to_proc.curry[2]) # => [2, 4]