How does the “#map(&proc)” idiom work when introspecting module classes?

前端 未结 4 1542
长情又很酷
长情又很酷 2021-02-13 13:29

Presenting the Idiom

I found an interesting but unexplained alternative to an accepted answer. The code clearly works in the REPL. For example:

module          


        
4条回答
  •  旧时难觅i
    2021-02-13 14:20

    The first thing to know is that:

    & calls to_proc on the object succeeding it and uses the proc produced as the methods' block.

    Now you have to drill down to how exactly the to_proc method is implemented in a specific class.

    1. Symbol

    class Symbol
      def to_proc
        Proc.new do |obj, *args|
          obj.send self, *args
        end
      end
    end
    

    Or something like this. From the above code you clearly see that the proc produced calls the method (with name == the symbol) on the object and passes the arguments to the method. For a quick example:

    [1,2,3].reduce(&:+)
    #=> 6
    

    which does exactly that. It executes like this:

    1. Calls :+.to_proc and gets a proc object back => #
    2. It takes the proc and passes it as the block to the reduce method, thus instead of calling [1,2,3].reduce { |el1, el2| el1 + el2 } it calls
      [1,2,3].reduce { |el1, el2| el1.send(:+, el2) }.

    2. Method

     class Method
       def to_proc
         Proc.new do |*args|
           self.call(*args)
         end
       end
     end
    

    Which as you can see it has a different implementation of Symbol#to_proc. To illustrate this consider again the reduce example, but now let as see how it uses a method instead:

    def add(x, y); x + y end
    my_proc = method(:add)
    [1,2,3].reduce(&my_proc)
    #=> 6
    

    In the above example is calling [1,2,3].reduce { |el1, el2| my_proc(el1, el2) }.

    Now on why the map method returns an Array instead of an Enumerator is because you are passing it a block, try this instead:

    [1,2,3].map.class
    #=> Enumerator
    

    Last but not least the grep on an Array is selecting the elements that are === to its argument. Hope this clarifies your concerns.

提交回复
热议问题