def do_n_times(n){ i = 1 while( i<=n ) yield i end } do_n_times( 3 ){ |x| puts "--->#{x}" } # --->1 # --->2 # --->3
上面是使用关键字 yeild 来调用代码块,而下面的例子,在方法定义的时候定义了一个Proc 参数( 索引到传入的块),这个 Proc 参数需放在参数列表的最后,然后在方法里调用 call 方法,来调用Proc 块。
注意这种使用方式和之前的方式,调用方法是一样的。
片段2 :
def do_n_times(n , &p){ i = 1 while( i<=n ) p.call(i) # 调用 Proc.call 方法 end } do_n_times( 3 ){ |x| puts "--->#{x}" } #注意这里的调用方式和之前的代码一样。 # --->1 # --->2 # --->3
下面的这种方式,你可以创建 Proc 对象,再传入到方法中. 这种方式在方法的定义中,参数 p 和普通的参数形式一样。
片段3 :
def do_n_times(n , p){ i = 1 while( i<=n ) p.call(i) end } p = Proc.new { |x| puts "--->#{x}" } do_n_times(3,p) # 这里直接传入Proc 对象 p # --->1 # --->2 # --->3
在片段2中 &p 参数需放到参数列表的最后位置,由于 block 参数传入方法的特殊。而这里则没有这种限制。
下面的代码片段,把两个数组的值加起来
片段4 :
a, b = [0,1,2], [3,4] sum = a.inject(0) { |total, x| total+x } # => 3 a数组的总和 sum = b.inject(sum) { |total, x| total+x } # => 10 a数组的总和加上 b数组的所有元素
上面的代码,两次调用 inject 方法,都使用了相同的 block . 对于这样的情况,可以通过定义一个 Proc 对象来简化代码
片段5 :
a, b = [0,1,2], [3,4] summation = Proc.new { |total,x| total+x } sum = a.inject(0, &summation) # => 3 sum = b.inject(sum, &summation) # => 10
使用 &作为前缀的参数,需要放到参数列表的最后。其实任何方法调用都可以传递一个 block ,尽管方法并没有期望传进来 block, 尽管方法内部并没有调用 yeild。
也就是说任何的方法调用都可以,传入一个 &参数,作为方法的最后一个参数。在一个方法调用中,& 符号通常出现在一个 Proc对象之前,实际上,它允许出现在
任何对象( 有to_proc方法的对象), Method 类有这样一个方法,所以,Method对象能传递给 iterators ,像Proc 对象那样。
在 Ruby1.9 中, Symbol 类定义了一个 to_proc 方法, 允许符号能在前面加 & 并传递给iterators . 当一个 symbol 通过这种方式传递,它被当成方法的名字,每个被迭代的对象都会调用该方法,如下
片段6 :
words = ['and', 'but', 'bike'] uppercase = words.map &:upcase #每个单词都调用upcase 方法 upper = words.map { |w| w.upcase } #这个和上面是等价的 # => ["AND", "BUT", "BIKE"]
下面的代码对一个对象数组以对象的某个属性排序, 运用&Symbol 的方法
class Person attr_accessor :name, :age def initialize(name,age) @name = name @age = age end end persons = [ Person.new('bbb',2), Person.new('aaa',3), Person.new('ccc',1),] by_attr = :name p persons.sort_by &by_attr by_attr = :age p persons.sort_by &by_attr
# => [#<Person:0xb7b6ce54 @name="aaa", @age=3>, #<Person:0xb7b6ce04 @name="bbb", @age=2>, #<Person:0xb7b6cddc @name="ccc", @age=1>]
# => [#<Person:0xb7b6cddc @name="ccc", @age=1>, #<Person:0xb7b6ce54 @name="bbb", @age=2>, #<Person:0xb7b6ce04 @name="aaa", @age=3>]
上面的代码可以对persons 对象根据给定的属性排序,通过 &Symbol 这种方式,可以根据给定的symbol ( 实际应用中该值应该是传入值 ), 当然这里只是按照sort_by 默认的排序方向来排序,如需要换方向可以调用 reverse 方法。