为什么to_proc不在Ruby改进中工作?

时间:2016-02-11 07:31:10

标签: ruby proc refinements

to_proc似乎不适用于优化中定义的方法:

module ArrayExtensions
  refine Array do
    def sum
      reduce(0, :+)
    end
  end
end

using ArrayExtensions

puts [[1, 2, 3]].map { |array| array.sum } # => 6
puts [[1, 2, 3]].map(&:sum) # => array.rb:13:in `map': undefined method `sum' for [1, 2, 3]:Array (NoMethodError)
puts [1, 2, 3].method(:sum).to_proc.call # => array.rb:14:in `method': undefined method `sum' for class `Array' (NameError)

这是预期的行为吗?有解决方法吗?

2 个答案:

答案 0 :(得分:3)

NB 以下答案对于旧版红宝石是正确的。在Ruby 2.5+ map(&:sum)按预期工作

Scoping of refinements仅限于当前上下文。由于优化是非全局,因此与 monkey patches 相反,任何尝试从外部调用精炼方法都会被阻止。在下面的代码中:

puts [[1, 2, 3]].map { |array| array.sum } # => 6

范围很好,我们在定义此细化的同一范围内。但是在这里:

puts [[1, 2, 3]].map(&:sum)

范围转移到Symbol class(!)的上下文。如文档中所述:

  

当控制权转移到范围之外时,细化将被停用。

这里的比喻是私人方法。尽管如此,虽然它完全与文档中所述,但我不确定这种行为是否有意。我相信,口译员应该照顾这些案件。但这个问题更适合解决Matz:)

P.S。好问题!

答案 1 :(得分:1)

当然是有意的。细化的范围是模块块或调用using的文件。在(&:sum)中,您没有(明确地)调用方法sum;你只有一个符号:sum。当使用Symbol#to_proc时,调用是在Ruby C实现中的某个地方完成的。这种环境是你的改进无效的地方。

解决方法是在该文件中显式调用该方法。