我们可以轻松定义一个方法,并使用一元&符号将其转换为块。
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转换为块时,是否可以传递其他参数?
答案 0 :(得分:6)
@sawa是对的。您可以使用curry
执行此操作。
Proc版本:
mult = proc {|a, b| a * b} # => #<Proc:0x00000002af1098@(irb):32>
[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]
答案 1 :(得分:1)
关于your comment:
奇怪,但它在演出期间交换了论据
实际上,参数顺序是保留的。
curry
返回一个新的proc,它有效地收集参数,直到有足够的参数来调用原始方法/ proc(基于它的arity)。这是通过返回中间过程来实现的:
def foo(a, b, c)
{ a: a, b: b, c: c }
end
curried_proc = foo.curry #=> #<Proc:0x007fd09b84e018 (lambda)>
curried_proc[1] #=> #<Proc:0x007fd09b83e320 (lambda)>
curried_proc[1][2] #=> #<Proc:0x007fd09b82cfd0 (lambda)>
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') #=> #<Proc:0x007fa31c2070d0 (lambda)>
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) #=> #<Proc:0x007fa31c2070d0 (lambda)>
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"]