读代码学RUBY之闭包

#代码来源:http://rubyer.me/blog/917顺便学习 Ruby的4种闭包:blocks, Procs, lambdas 和 Methods。
#first
class Array
  def iterate!
    self.each_with_index do |n, i|
      self[i] = yield(n)
      yield(n)
    end
  end
end

array = [1, 2, 3, 4]

array.iterate! do |x|
  x ** 2
end

puts array.inspect

# => [1, 4, 9, 16]
#second
class Array
    def iterate!(&code)  #为iterate!传递一个参数&code,&表示这个参数是block。
        self.each_with_index do |n,i|
            self[i] = code.call(n)  #在iterate!中没有使用yield而是call。
        end
    end
end

array.iterate! do |n|
    n ** 2
end

puts array.inspect

#third
# ---PROC Procs 过程block与Proc惟一的不同是:block是不能保存的Proc,一次性的。
square = Proc.new do |n|
    n ** 2
end

class Array
  def iterate!(code) #now these is not &code, not null, but code !!
      #注意:并没有在 iterate!的参数头部添加&,因为Proc只是一个普通类,不需要特殊处理。
    self.each_with_index do |n, i|
      self[i] = code.call(n)
    end
  end
end

array.iterate! square 

puts array.inspect

  

来源:http://rubyer.me/blog/917  

首先,我们打开Array,并添加进iterate!方法。方法名以!结尾表示危险方法,引起注意。现在我们就可能像使用collect!一样使用iterate!

与属性不同,在方法中不需要指定block的名字,而是使用yield来调用。yield会执行block中的代码。同时,注意我们是怎么把n(each_with_index当前处理的数字)传给yield的。传给yield的参数即对应了block中的参数(||中的部分)。现在n就能被block调用并在yield调用中返回n**2。
整个调用如下:
1、一个整数组成的数组调用iterate!
2、当yield被调用时,把n(第一次为1,第二次为2,…)传给block
3、block对n进行n**2。因为是最后一行,自动作为结果返回。
4、yield得到block的结果,并把值重写到array里(这里用了self,在class和module的定义中,self代表这个class或这module对象,拓展阅读:http://fuliang.iteye.com/blog/272370
5、数据中每个对象执行相同操作。

 

def callbacks(procs)
  procs[:starting].call

  puts "Still going"

  procs[:finishing].call
end

callbacks(:starting => Proc.new { puts "Starting" },
          :finishing => Proc.new { puts "Finishing" })

# => Starting
# => Still going
# => Finishing

 1、(:starting => Proc.new { puts "Starting" }, :finishing => Proc.new { puts "Finishing" } ) 这里定义了一个哈希表或者说字串符號 (Symbol) 。(一個 Symbol 物件皆為冒號開頭,例如 :foo 或 :foo_bar。它的作用就是代表一個名字,最大的作用就是當做 Hash 的鍵 (key),例如{ :foo => 1, :bar => 2 },在這裡我們只需要一個識別的名字,不需要使用字串物件。使用 Symbol 寫法更簡潔和獲得效能上的好處。)

   2、:starting => Proc.new { puts "Starting" } 键KEY为 :starting,键VALUE为 一个Procs 过程。

   3、procs[:starting].call 直接调用 储存在 procs[:starting] 中的 Procs 过程

 BTW:什么时候用blocks而不用Procs呢?我一般这样判断:
1、Block:方法把一个对象拆分成很多片段,并且你希望你的用户可以与这些片段做一些交互。
2、Block:希望自动运行多个语句,如数据库迁移(database migration)。
3、Proc:希望多次复用一段代码。
4、Proc:方法有一个或多个回调方法(callbacks)。


未完,明天继续。

 

posted @ 2012-02-23 01:25  喻头快跑  阅读(344)  评论(0编辑  收藏  举报