2013-02-14 62 views
31

我正在学习rails并关注this thread。我坚持使用to_proc方法。我认为符号只能作为字符串的替代品(它们就像字符串,但在内存方面更便宜)。如果还有其他东西我错过了符号,请告诉我。请以简单的方式解释to_proc的含义及其用途。to_proc方法是什么意思?

回答

77

的某些方法将块,并且这种模式经常出现的块:

{|x| x.foo} 

,人们想编写更简洁的方式。为了做到这一点,一个符号,方法Symbol#to_proc,隐式类别转换和&运算符组合使用。如果在参数位置上将&放在Proc实例的前面,则会将其解释为块。如果将Proc实例以外的其他内容与&合并,则隐式类转换将尝试使用该对象上定义的to_proc方法将其转换为Proc实例(如果有)。在Symbol实例的情况下,to_proc作品以这样的方式

:foo.to_proC# => ->x{x.foo} 

例如,假设您这样写:

bar(&:foo) 

&运营商与:foo相结合,这是不是一个Proc实例,所以隐式类别转换将Symbol#to_proc应用于它,它给出->x{x.foo}。该&现在适用于这一点,并解释为一个块,这给:

bar{|x| x.foo} 
+3

感谢您的解释+1 :) – swapnesh 2013-02-14 18:29:52

+0

另外,根据,它是20运行时间更快。 – 2015-05-22 13:23:45

+0

我知道'&proc'给出了一个块,'&x'结果x变成了proc,然后整个事情也给出了一个块。我也明白Symbol有to_proc方法。然而,我不明白的部分,我觉得这个答案缺乏,是如何符号和方法连接。我的意思是它不像所有的方法都可以通过符号名称得到 – 2016-02-28 09:35:17

39

解释这是一些例子最简单的方法。

(1..3).collect(&:to_s) #=> ["1", "2", "3"] 

相同:

(1..3).collect {|num| num.to_s} #=> ["1", "2", "3"] 

[1,2,3].collect(&:succ) #=> [2, 3, 4] 

相同:

[1,2,3].collect {|num| num.succ} #=> [2, 3, 4] 

to_proc返回一个Proc对象,它响应给定的方法由符号。 所以在第三种情况下,数组[1,2,3]调用它的collect方法和。 succ是由Array类定义的方法。所以这个参数是收集数组中每个元素并返回它的后继的简短方式,并从中创建一个导致[2,3,4]的新数组。符号:succ被转换为Proc对象,因此它调用Array的succ方法。

+3

@Dilon +1为例:) – swapnesh 2013-02-14 18:46:41

7

对我来说,最清晰的解释是看到它的简单实现。下面是它可能看起来像如果我重新实现符号#to_proc:

class Symbol # reopen Symbol class to reimplement to_proc method 
    def to_proc 
    ->(object) { object.send(self) } 
    end 
end 

my_lambda = :to_s.to_proc 

puts my_lambda.(1) # prints '1'; .() does the same thing as .call() 
puts my_lambda.(1).class # prints 'String' 

puts [4,5,6].map(&:to_s) # prints "4\n5\n6\n" 
puts [4,5,6].map(&:to_s).first.class # prints 'String' 
+1

This!顺便说一下,它应该不是'my_to_proc'你试图在'Symbol'类上修补的方法吗? – 2016-11-09 14:58:27

+0

@AgungSetiawan好赶上!相反,我重命名了该调用,以便调用to_proc而不是my_to_proc。 – 2016-11-10 08:00:32

1

任何人还是有点难倒,运行下面的代码可能会使事情更清晰一点:

class Symbol 
    def to_proc 
    proc do |obj| 
     puts "Symbol proc: #{obj}.send(:#{self})" 
     obj.send(self) 
    end 
    end 
end 

class Array 
    def map(&block) 
    copy = self.class.new 
    self.each do |index| 
     puts "Array.map: copy << block.call(#{index})" 
     copy << block.call(index) 
    end 
    copy 
    end 
end 

remapped_array = [0, 1, 2].map &:to_s 
puts "remapped array: #{remapped_array.inspect}" 

这些都不是Symbol.to_procArray.map的实际实现,它们只是我用来演示map &:to_s和类似调用如何工作的简化版本。