【问题标题】:Difference between passing &:method and :method as function arguments in rubyruby 中将 &:method 和 :method 作为函数参数传递的区别
【发布时间】:2013-06-16 20:58:23
【问题描述】:

我正在努力理解何时使用 & 符号将符号传递给表示方法的函数。例如,如果我想计算范围 1..10 的总和,我可以执行以下操作:

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

这最初让我相信,如果你想传递一个符号来定义一个在函数中“神奇地”使用的方法,你会将函数名作为符号传递。但是后来我在rails中看到了这样的东西:

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

如果我理解正确,&:price 与调用 :price.to_proc 相同。我不明白上面的工作原理。

【问题讨论】:

  • 这个和Enumerable#Inject无关,我只是拿来举例子。
  • :+ 的效果在您的示例中与inject 紧密相关,而&:price 则不然。
  • 感谢您为我解决这个问题。

标签: ruby-on-rails ruby metaprogramming function-pointers symbols


【解决方案1】:

在方法调用的实参列表中,&object是内置语法,会

  1. 使用object.to_procobject 转换为Proc
  2. 将 Proc 作为方法的块参数传递

Symbol#to_proc 将符号(例如 :the_symbol)转换为 proc {|obj| obj.send(:the_symbol)}。只要object 响应to_proc 方法并返回一个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(:+) 表明 inject 接受符号作为参数。符号的使用方式是特定于方法的行为。在inject 的特殊情况下,它与(1..10).inject{|a, b| a.send(:+, b)} 具有相同的效果。它只是一个简单的普通参数,效果取决于接受符号作为参数的方法的实现。

注意,ActiveSupport 中的sum 接受带有单个参数的块,其效果是“将原始序列中的值映射到新序列中并计算它们的总和”,所以

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

等价于

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

返回值与以下相同,但不会产生中间临时数组:

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

【讨论】:

  • 我认为 & 是 to_proc 的简写,而不是 to_sym,我错了吗?
  • :price.to_proc 如何与 sum 交互?我的意思是,我假设这会以某种方式转换为 product.price,并将这些价格相加。
猜你喜欢
  • 2016-03-05
  • 1970-01-01
  • 1970-01-01
  • 2017-02-28
  • 2015-04-07
  • 2013-04-11
  • 1970-01-01
  • 1970-01-01
  • 2010-09-20
相关资源
最近更新 更多