你能提供参数到Ruby中的映射(&:方法)语法?
你可能熟悉下面的Ruby速记( a
是一个数组):
a.map(&:method)
例如,在irb中尝试以下内容:
>> a=[:a, 'a', 1, 1.0] => [:a, "a", 1, 1.0] >> a.map(&:class) => [Symbol, String, Fixnum, Float]
语法a.map(&:class)
是a.map {|x| x.class}
的缩写 a.map {|x| x.class}
。
阅读“ 在Ruby中map(&:name)是什么意思 ”中有关此语法的更多信息?
通过语法&:class
,你正在为每个数组元素做一个方法调用class
。
我的问题是:你可以提供参数的方法调用? 如果是的话,怎么样?
例如,你如何转换下面的语法
a = [1,3,5,7,9] a.map {|x| x + 2}
到&:
语法?
我并不是build议&:
语法更好。 我只是对使用带有参数的&:
syntax的机制感兴趣。
我假设你知道+
是Integer类的一个方法。 您可以在irb中尝试以下内容:
>> a=1 => 1 >> a+(1) => 2 >> a.send(:+, 1) => 2
你可以像这样在Symbol
上创build一个简单的补丁:
class Symbol def with(*args, &block) ->(caller, *rest) { caller.send(self, *rest, *args, &block) } end end
这将使您不仅可以做到这一点:
a = [1,3,5,7,9] a.map(&:+.with(2)) # => [3, 5, 7, 9, 11]
但也有很多其他很酷的东西,比如传递多个参数:
arr = ["abc", "babc", "great", "fruit"] arr.map(&:center.with(20, '*')) # => ["********abc*********", "********babc********", "*******great********", "*******fruit********"] arr.map(&:[].with(1, 3)) # => ["bc", "abc", "rea", "rui"] arr.map(&:[].with(/a(.*)/)) # => ["abc", "abc", "at", nil] arr.map(&:[].with(/a(.*)/, 1)) # => ["bc", "bc", "t", nil]
甚至可以使用inject
,它将两个parameter passing给块:
%w(abecd ab cd).inject(&:gsub.with('cde')) # => "cdeeecde"
或者把速记块传给速记块的东西超级酷:
[['0', '1'], ['2', '3']].map(&:map.with(&:to_i)) # => [[0, 1], [2, 3]] [%w(ab), %w(cd)].map(&:inject.with(&:+)) # => ["ab", "cd"] [(1..5), (6..10)].map(&:map.with(&:*.with(2))) # => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
以下是我与@ArupRakshit进一步解释的一次对话:
你能提供参数到Ruby中的映射(&:方法)语法?
正如在下面的注释中提到的@amcaplan,如果你重命名with
方法来call
,你可以创build一个更短的语法。 在这种情况下,ruby为这个特殊的方法有一个内置的快捷方式。
所以你可以像这样使用上面的代码:
class Symbol def call(*args, &block) ->(caller, *rest) { caller.send(self, *rest, *args, &block) } end end a = [1,3,5,7,9] a.map(&:+.(2)) # => [3, 5, 7, 9, 11] [(1..5), (6..10)].map(&:map.(&:*.(2))) # => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
对于你的例子可以完成a.map(&2.method(:+))
。
Arup-iMac:$ pry [1] pry(main)> a = [1,3,5,7,9] => [1, 3, 5, 7, 9] [2] pry(main)> a.map(&2.method(:+)) => [3, 5, 7, 9, 11] [3] pry(main)>
下面是它的工作原理 :-
[3] pry(main)> 2.method(:+) => #<Method: Fixnum#+> [4] pry(main)> 2.method(:+).to_proc => #<Proc:0x000001030cb990 (lambda)> [5] pry(main)> 2.method(:+).to_proc.call(1) => 3
2.method(:+)
给出一个Method
对象。 然后,在2.method(:+)
,实际上调用了#to_proc
方法,这使得它成为一个Proc
对象。 然后按照什么你在Ruby中调用&:操作符? 。
正如您链接的post所确认的, a.map(&:class)
不是a.map {|x| x.class}
a.map {|x| x.class}
但为a.map(&:class.to_proc)
。
这意味着to_proc
在&
运算符to_proc
被调用。
所以你可以直接给它一个Proc
来代替:
a.map(&(Proc.new {|x| x+2}))
我知道最有可能的是,这会打败你的问题的目的,但是我不能看到任何其他的方式 – 不是你指定要调用的方法,而是传递一些响应to_proc
东西。
简短的回答:不。
在@ rkon的回答之后,你也可以这样做:
a = [1,3,5,7,9] a.map &->(_) { _ + 2 } # => [3, 5, 7, 9, 11]
自己修补核心类,而不是像公认的答案那样,使用Facets gem的function更简洁,
require 'facets' a = [1,3,5,7,9] a.map &:+.(2)