2015-02-07 69 views
5

我喜欢如何在Ruby中,你可以通过方法为块,像这样使用Symbol#to_proc与自定义方法符号#to_proc

[1.0, 2.0, 3.0].map(&:to_i) 
#=> [1, 2, 3] 

我也可以定义自己的拉姆达,times_two,并把它作为一个块以及:

times_two = ->(x) {x * 2} 

[1, 2, 3].map(&times_two) 
#=> [2, 4, 6] 

虽然我貌似不能times_two作为符号:

[1, 2, 3].map(&:times_two) 
#=> ArgumentError: wrong number of arguments (0 for 1) 

然而,当我试图做同样的方法我得到一个错误:

def times_three(x) 
    x * 3 
end 

[1, 2, 3].map(&times_three) 
#=> ArgumentError: wrong number of arguments (0 for 1) 

[1, 2, 3].map(&:times_three) 
#=> ArgumentError: wrong number of arguments (0 for 1) 

我猜我不能这样做,因为times_three是一种方法,而不是一个Proc。

那么如何定义自定义方法,以便在上面的第一个示例中以to_i的方式使用Symbol#to_proc方式?

例如,我该如何做到这一点?

[1, 2, 3].map(&:times_three) 
#=> [3, 6, 9] 

编辑: 我看了视频下面贴,显然可以使用method方法去接近符号#to_proc:

def times_three(x) 
    x * 3 
end 

t_three = method(:times_three) 
[1, 2, 3].map(&t_three) 
#=> [3, 6, 9] 

但是,它不是相当符号#to_proc:

[1, 2, 3].map(&:t_three) 
#=> NoMethodError: undefined method `t_three' for 1:FixNum 

回答

5
class Integer 
    def times_three 
    return self * 3 
    end 
end 

,因为times_three现在是Integer类的方法,你可以做符号来处理...

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

如果你想访问的方法不是对象类的一部分,但作用于对象,你需要将对象作为参数传递给方法...

def times_three(x) 
    x * 3 
end 

[1, 2, 3].map{|i| times_three(i) } 

symbol to proc需要使用该对象作为接收者。

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

相当于

[1, 2, 3].map{|i| i.some_action} 
+0

非常感谢这个清晰的解释,史蒂夫。现在我知道如何做到这一点,是否可以接受的做法是用这种方法来修补核心类以清理复杂或重复的块? – garythegoat 2015-02-08 00:07:00

+0

嗯,是的,只要意图清楚,并有好处,猴子补丁肯定没问题。 本周我有一个rails应用程序,其中强制性输入字段在标签中有星号,例如, “'名字*''和''城市*'',企业突然想要所有的星号变成红色的字体颜色。我可以写一个像red_asterisk('First Name *')这样的辅助方法,但是更容易的方法是修改String类的First Name * red_asterisk然后在'*'上执行全局查找/替换操作。 ''所以它变成了'*'。red_asterisk' – SteveTurczyn 2015-02-08 00:23:11

+0

史蒂夫,正如你所知道的那样,'return'是不需要的。然而,“自我”是。我假设'self'必须是明确的,例如'*','%'等方法都是用语法糖调用的。你或其他人知道这是否属实? – 2015-02-08 04:39:59

1

您必须在IntegerNumeric上定义times_three

符号来解释PROC通过彼得库珀:现在https://www.youtube.com/watch?v=aISNtCAZlMg

+3

而不是链接到随机参考,你应该写简短的说明/它拷贝到这里,给链接源为您anwser。 – Smar 2015-02-07 23:24:14

+0

感谢您的视频。然而,它并没有说明为什么我必须在Integer或Numeric上定义'times_three''。它显示了Ruby在采用Symbol#to_proc之前如何在类上实现'to_proc'',但该视频并未显示如何以这种方式定义自己的方法。 – garythegoat 2015-02-07 23:36:45

+1

@garythegoat:它确实显示了'Symbol#to_proc'是如何实现的,即它在块的第一个参数上调用方法,将块的其他参数作为方法调用的参数传递。在你的情况下,块的第一个参数是'1'(在第一次迭代中),并且没有其他参数,所以需要定义'Symbol#to_proc'调用'1.times_three',ergo,'times_three'在'1'的一个类中,即Fixnum,Integer,Numeric,Object,Kernel或BasicObject。不幸的是,[文档是废话](http://ruby-doc.org/core-2.2.0/Symbol.html#method-i-to_proc),... – 2015-02-08 01:08:24