Difference between passing &:method and :method as function arguments in ruby

好久不见. 提交于 2019-12-11 05:40:39

问题


I'm struggling in understanding when to use the ampersand in passing symbols to functions representing a method. For example, If I wanted to calculate the sum of the range 1..10, I could do the following:

(1..10).inject(:+)

This originally lead me to believe that if you wanted to pass a symbol to define a method to "Magically" be used in the function, you would pass the function name as a symbol. But then I see something like this in rails:

total = Product.find(product_list).sum(&:price)

If I understand correctly, &:price is the same as calling :price.to_proc. I don't understand how the above works.


回答1:


In actual parameter list of a method call, &object is built-in syntax, which will

  1. convert object to a Proc using object.to_proc
  2. pass the Proc as the block parameter of the method

Symbol#to_proc converts the symbol (eg. :the_symbol) to proc {|obj| obj.send(:the_symbol)}. And you can use this syntax whenever object responds to to_proc method and returns a Proc.

abc = "aha~"
class << abc
  def to_proc
    proc {|obj| obj.to_i * 2 }
  end
end
p ["1", "2", "3"].map(&abc)
#=> [2, 4, 6]

(1..10).inject(:+) shows that inject accepts a symbol as parameter. How the symbol is used is method specific behavior. In inject's special case, it has the same effect as (1..10).inject{|a, b| a.send(:+, b)}. It's just a simple, normal parameter, the effect depends on the implementation of the method that accept the symbol as parameter.

Note that sum in ActiveSupport accepts a block with single parameter, which has the effect "map values in the original sequence to new ones and calculate the sum of them", so

total = Product.find(product_list).sum(&:price)

is equivalent as

total = Product.find(product_list).sum(&proc{|p| p.send(:price)})
# or you may write
total = Product.find(product_list).sum{|p| p.price }

which has the same return value as the following but won't produce intermediate temp array:

total = Product.find(product_list).map{|p| p.price}.sum


来源:https://stackoverflow.com/questions/17206254/difference-between-passing-method-and-method-as-function-arguments-in-ruby

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!