Can you supply arguments to the map(&:method) syntax in Ruby?

后端 未结 7 1122
面向向阳花
面向向阳花 2020-11-22 16:59

You\'re probably familiar with the following Ruby shorthand (a is an array):

a.map(&:method)

For example, try the followin

相关标签:
7条回答
  • 2020-11-22 17:40

    Short answer: No.

    Following @rkon's answer, you could also do this:

    a = [1,3,5,7,9]
    a.map &->(_) { _ + 2 } # => [3, 5, 7, 9, 11]
    
    0 讨论(0)
  • 2020-11-22 17:44

    I'm not sure about the Symbol#with already posted, I simplified it quite a bit and it works well:

    class Symbol
      def with(*args, &block)
        lambda { |object| object.public_send(self, *args, &block) }
      end
    end
    

    (also uses public_send instead of send to prevent calling private methods, also caller is already used by ruby so this was confusing)

    0 讨论(0)
  • 2020-11-22 17:47

    For your example can be done 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)> 
    

    Here is how it works :-

    [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(:+) gives a Method object. Then &, on 2.method(:+), actually a call #to_proc method, which is making it a Proc object. Then follow What do you call the &: operator in Ruby?.

    0 讨论(0)
  • 2020-11-22 17:49

    As the post you linked to confirms, a.map(&:class) is not a shorthand for a.map {|x| x.class} but for a.map(&:class.to_proc).

    This means that to_proc is called on whatever follows the & operator.

    So you could give it directly a Proc instead:

    a.map(&(Proc.new {|x| x+2}))
    

    I know that most probably this defeats the purpose of your question but I can't see any other way around it - it's not that you specify which method to be called, you just pass it something that responds to to_proc.

    0 讨论(0)
  • 2020-11-22 17:53

    There is another native option for enumerables which is pretty only for two arguments in my opinion. the class Enumerable has the method with_object which then returns another Enumerable.

    So you can call the & operator for a method with each item and the object as arguments.

    Example:

    a = [1,3,5,7,9]
    a.to_enum.with_object(2).map(&:+) # => [3, 5, 7, 9, 11]
    

    In the case you want more arguments you should repeat the proccess but it's ugly in my opinion:

    a = [1,3,5,7,9]
    a.to_enum.with_object(2).map(&:+).to_enum.with_object(5).map(&:+) # => [8, 10, 12, 14, 16]
    
    0 讨论(0)
  • 2020-11-22 17:56

    Instead of patching core classes yourself, as in the accepted answer, it's shorter and cleaner to use the functionality of the Facets gem:

    require 'facets'
    a = [1,3,5,7,9]
    a.map &:+.(2)
    
    0 讨论(0)
提交回复
热议问题