符号链接和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)