Ruby元编程
你能在Ruby中提供map(&:method)语法的参数吗?
问题
a = [1,3,5,7,9] a.map {|x| x + 2} # => [3, 5, 7, 9, 11]
解决办法
您可以在with上创建一个简单的补丁,如下所示:
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] [['0', '1'], ['2', '3']].map(&:map.with(&:to_i)) # => [[0, 1], [2, 3]] [%w(a b), %w(c d)].map(&:inject.with(&:+)) # => ["ab", "cd"] [(1..5), (6..10)].map(&:map.with(&:*.with(2))) # => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
with升级
如果将with方法重命名为call,则可以创建更短的语法。在这种情况下,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]]
另一种解决办法:
引入Facets gem,而不是自己修补核心类
require 'facets' a = [1,3,5,7,9] a.map &:+.(2) # => [3, 5, 7, 9, 11]