符号链接和to_proc

这是众所周知的Rubyist &将在符号上调用to_proc ,所以

 [:a, :b, :c].map(&:to_s) 

相当于

 [:a, :b, :c].map { |e| e.to_s } # => ["a", "b", "c"] 

假设我想在to_s之后调用另一个方法,这两个实现将起作用:

 [:a, :b, :c].map { |e| e.to_s.upcase } [:a, :b, :c].map(&:to_s).map(&:upcase) 

我的问题是,有没有办法在一个参数中链接& Symbol#to_proc调用? 就像是:

 [:a, :b, :c].map(&:to_s:upcase) 

谢谢!

如果你只是这样做:

 %i[abc].map { |e| e.to_s.upcase } 

然后只需使用块并继续处理更重要的事情。 如果您真的在进行一系列Enumerable调用并且发现块太吵了:

 %i[abc].map { |e| e.to_s.upcase }.some_chain_of_enumerable_calls... 

然后你可以把你的逻辑扔进一个lambda来帮助清理外观:

 to_s_upcase = lambda { |e| e.to_s.upcase } %i[abc].map(&to_s_upcase).some_chain_of_enumerable_calls... 

或者把它扔进一个方法并说:

 %i[abc].map(&method(:to_s_upcase)).some_chain_of_enumerable_calls... 

无论哪种方式,你都会给你的一些逻辑命名(这几乎是所有&:symbol为你做的),使代码更易读,更容易理解。 在to_s.upcase的特定情况下,这一点to_s.upcase ,但是当块变大时,这些方法非常有用。

您需要提前定义一些方法,但这将具有普遍性。 你可以这样做:

 class Symbol def * other ->x{x.send(self).send(other)} end end [:a, :b, :c].map(&:to_s * :upcase) [:a, :b, :c].map(&:to_s * :capitalize) ... 

我选择*作为功​​能组合的方法。

如果您认为可以使用第三个符号,则可以定义如下:

 class Proc def * other ->x{call(x).send(other)} end end 

所以只是为了好玩(并且为了certificate几乎所有东西都可以在ruby中进行一些努力)我们可以在Symbol上定义一个方法(我们称之为Symbol#chain )来提供这个function和更多function

 class Symbol def proc_chain(*args) args.inject(self.to_proc) do |memo,meth| meth, *passable_args = [meth].flatten passable_block = passable_args.pop if passable_args.last.is_a?(Proc) Proc.new do |obj| memo.call(obj).__send__(meth,*passable_args,&passable_block) end end end alias_method :chain, :proc_chain end 

然后可以像这样调用它

 [:a, :b, :c].map(&:to_s.chain(:upcase)) #=> ["A","B","C"] # Or with Arguments & blocks [1,2,3,4,5].map(&:itself.chain([:to_s,2],:chars,[:map,->(e){ "#{e}!!!!"}])) #=> => [["1!!!!"], ["1!!!!", "0!!!!"], ["1!!!!", "1!!!!"], # ["1!!!!","0!!!!", "0!!!!"], ["1!!!!", "0!!!!", "1!!!!"]] 

甚至可以作为独立使用

 p = :to_s.chain([:split,'.']) p.call(123.45) #=> ["123","45"] # Or even [123.45,76.75].map(&p) #=> => [["123", "45"], ["76", "75"]] 

虽然我们正在使用语法,但是使用to_proc方法修补数组猴子怎么样?

 class Array def to_proc return :itself.to_proc if empty? ->(obj) { drop(1).to_proc.call(first.to_proc.call(obj)) } end end ["foo", "bar", "baz"].map(&[:capitalize, :swapcase, :chars, ->a{ a.join("-") }]) # => ["fOO", "bAR", "bAZ"] 

请参阅repl.it:https://repl.it/JS4B/1

没有办法使用符号链接到proc。

但是,你可以将一个方法修补到你要映射的类,然后调用它。

 class Symbol def to_upcase_str self.to_s.upcase end end [:a, :b, :c].map(&:to_upcase_str)