2014-01-30 60 views
3

我发现,实现自定义符号#to_proc在Ruby中此示例代码:为什么Symbol#to_proc具有这种类型的行为?

class Symbol 
    def to_proc 
    puts "In the new Symbol#to_proc!" 
    Proc.new { |obj| obj.send(self) } 
    end 
end 

它包括额外的“放......”字符串,以确保它没有内置的方法。当我执行的代码

p %w{ david black }.map(&:capitalize) 

结果是:

In the new Symbol#to_proc! 
["David", "Black"] 

但它为什么不这样呢?

In the new Symbol#to_proc! 
["David"] 
In the new Symbol#to_proc! 
["Black"] 

我的逻辑是这样的:map将元素一个接一个阻塞。块取第一个元素并执行.to_proc,而不是第二个。但为什么只执行一次?

+0

@bjhaid:这不是该答案的重复。完全一样。 –

+1

@bjhaid:恩,是的,我要继续前进,不同意你在这里。 –

+0

http://stackoverflow.com/questions/1961030/ruby-ampersand-colon-shortcut – andHapp

回答

3

在Ruby中,地图可与一个块。 &运营商在它后面的对象上调用to_proc,并将从调用to_proc返回的值传递给映射为block。有了这些信息,我们再来看看你的例子。在你的例子中,&:capitalize将致电方法:capitalize。因为,:capitalize是一个Symbol,它将在Symbol类上调用to_proc,由您重新定义。

:capitalize.to_proc 

将返回:

In the new Symbol#to_proc! 
=> #<Proc:[email protected](irb):4> 

&操作者将使用返回的PROC对象,并传递进程内对象映射为一个块。在您重新定义的to_proc方法定义中,puts刚刚得到执行,并且从puts打印到控制台(假设您正在控制台中运行此操作),您将看到它打印出来。它永远不会传递给地图,所以你永远不会看到它打印两次。

但是,如果您想要预期的行为,请使用第一个答案。希望能帮助到你。

+0

这是一个完美的答案,现在我明白发生了什么。谢谢! – rubybaseddev

6

to_proc方法被调用一次以返回一个Proc对象,然后重复使用该对象,以便您看到正确的行为。

如果移动内卖出期权,你会看到你期待什么:

class Symbol 
    def to_proc 
    Proc.new { |obj| 
     puts "In the new Symbol#to_proc!" 
     obj.send(self) 
    } 
    end 
end 
+0

谢谢你的解释,但我不明白为什么Proc对象只创建一次。为什么每个地图块调用都没有新的Proc对象?我确信Ruby正确执行代码,但我无法找到这种情况的很好解释。 – rubybaseddev

+1

为什么你会想要一个全新的proc每个循环?这是非常浪费的,因为'map'和类似函数的全部概念都是对许多对象应用完全相同的功能。如果你想对每个元素应用不同的函数,那么你应该使用'each'并在其中定制一段代码。这给你最大的灵活性。 – tadman