What does map(&:name) mean in Ruby?

后端 未结 16 2969
时光取名叫无心
时光取名叫无心 2020-11-21 05:34

I found this code in a RailsCast:

def tag_names
  @tag_names || tags.map(&:name).join(\' \')
end

What does the (&:name)

16条回答
  •  既然无缘
    2020-11-21 05:54

    Two things are happening here, and it's important to understand both.

    As described in other answers, the Symbol#to_proc method is being called.

    But the reason to_proc is being called on the symbol is because it's being passed to map as a block argument. Placing & in front of an argument in a method call causes it to be passed this way. This is true for any Ruby method, not just map with symbols.

    def some_method(*args, &block)
      puts "args: #{args.inspect}"
      puts "block: #{block.inspect}"
    end
    
    some_method(:whatever)
    # args: [:whatever]
    # block: nil
    
    some_method(&:whatever)
    # args: []
    # block: #
    
    some_method(&"whatever")
    # TypeError: wrong argument type String (expected Proc)
    # (String doesn't respond to #to_proc)
    

    The Symbol gets converted to a Proc because it's passed in as a block. We can show this by trying to pass a proc to .map without the ampersand:

    arr = %w(apple banana)
    reverse_upcase = proc { |i| i.reverse.upcase }
    reverse_upcase.is_a?(Proc)
    => true
    
    arr.map(reverse_upcase)
    # ArgumentError: wrong number of arguments (1 for 0)
    # (map expects 0 positional arguments and one block argument)
    
    arr.map(&reverse_upcase)
    => ["ELPPA", "ANANAB"]
    

    Even though it doesn't need to be converted, the method won't know how to use it because it expects a block argument. Passing it with & gives .map the block it expects.

提交回复
热议问题