为什么Ruby的符号proc会调用count方法而不是:count哈希键?

时间:2013-11-12 23:01:30

标签: ruby

鉴于此irb会议:

[2.0.0p195]> arr = [{count: 5}, {count: 6}, {count: 7}]
=> [{:count=>5}, {:count=>6}, {:count=>7}]
[2.0.0p195]> arr.collect(&:count)
=> [1, 1, 1]

[2.0.0p195]> arr.collect(&:count).reduce(:+)
=> 3
[2.0.0p195]> arr.collect {|e| e[:count]}.reduce(:+)
=> 18

我可以在collect或使用阻止时解决Hash上的方法解决此问题的唯一方法吗?

3 个答案:

答案 0 :(得分:3)

&安培;表示在其参数上调用#to_proc,在Symbol class implements this上创建一个基于符号调用方法名称的Proc - 所以&:symbol表示“在传入的对象上调用#symbol方法”。基本上,你得到的就是这相当于:

arr.collect{|obj| obj.send(:count)}

由于Hash根本不会响应“count”方法来获取:count键的值 - 也就是说,Hash#countHash#[](:count)不同,(尽管{{ 3}}确实为你做了这个),你坚持使用块方法。

答案 1 :(得分:2)

另一种方法是创建一个lambda,如果您多次编写同一个块,则非常有用:

fetch_count = -> x{x[:count]}
arr.collect(&fetch_count) #=> [5, 6, 7]

# If hash only has one value as in example:
arr.collect(&values).flatten #=> [5, 6, 7]

答案 2 :(得分:2)

呼叫&的实施在符号上如下(或多或少):

class Symbol
  def to_proc
    Proc.new { |obj| obj.send self }
  end
end

你可以看到它所做的一切(当与#map结合使用时)正在调用与枚举的每个成员上提供的符号相对应的方法。

如果你真的想通过使用OpenStruct而不是哈希来解决这个问题,你可以通过方法式访问元素来解决这个问题:

[{test: 1}].map { |h| OpenStruct.new(h) }.map &:test                                          
#=> [1]

或者发明一个除&之外还要执行哈希访问所需操作的运算符,如果稍后我有空闲时间,我可以重新审视这个挑战!

编辑:我已退回

这很hacky但是你可以通过使用一元~进行扩充来修补符号以提供你想要的功能:

# Patch
class Symbol
  def ~@
    ->(obj){ obj[self] }
  end
end

# Example usage:
[{count: 5}, {count: 6}, {count: 7}].map &~:count                                             
#=> [5, 6, 7]

如果像Ruby这样的免费语言没有您想要的功能,您可以随时将其构建: - )

免责声明:这可能是一个糟糕的主意。