Ruby元编程

Table of Contents

你能在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]

外链

Date: 2019-07-31 Wed 20:21