读代码学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
首先,我们打开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)。
未完,明天继续。