我发现这个示例代码在Ruby中实现了自定义Symbol#to_proc:
class Symbol
def to_proc
puts "In the new Symbol#to_proc!"
Proc.new { |obj| obj.send(self) }
end
end
它包含额外的“puts ...”字符串,以确保它不是内置方法。当我执行代码
时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逐个产生元素来阻止。 Block获取第一个元素并执行.to_proc,而不是第二个元素。但为什么只执行一次执行?
答案 0 :(得分:6)
调用to_proc
方法一次以返回随后重复使用的Proc对象,这样您就可以看到正确的行为。
如果你把内线放进去,你会看到你期待的东西:
class Symbol
def to_proc
Proc.new { |obj|
puts "In the new Symbol#to_proc!"
obj.send(self)
}
end
end
答案 1 :(得分:3)
在Ruby中,map使用块。 &
运算符在其后面的对象上调用to_proc
,并将调用to_proc
返回的值传递给block
。有了这些信息,让我们再看看你的例子。在您的示例中,&:capitalize
将导致to_proc
上的:capitalize
方法调用。由于:capitalize
是一个符号,它将在Symbol类上调用to_proc
,由您重新定义。
:capitalize.to_proc
将返回:
In the new Symbol#to_proc!
=> #<Proc:0x007fa08183df28@(irb):4>
&
运算符将使用返回的Proc对象,并将该proc对象传递给map作为块。在重新定义的to_proc
方法定义中,puts
刚刚执行,并且puts
打印到控制台(假设您在控制台中运行它),您将看到它已打印。它永远不会传递给地图,所以你永远不会看到它打印两次。
但是,如果您想要您期望的行为,请使用第一个答案。希望它有所帮助。