ruby

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 方法。

原文地址:https://www.cnblogs.com/laoquans/p/3932788.html