在Ruby中块是重点也是难点下面我把这两天学习当中的遇到的知识点做了一些总结。
# 1.1block可以用来做循环array = %w(This is my blog about Ruby)array.each{|x| print x + " "}# 1.2块变量也同样适用多重赋值规则hash = {x: 'this', y: 'why', z: 'i\'m'}hash.each{|key, value| print [key,value]}# 2.1块可以隐藏常规处理file = File.open("sample.txt")file.each do |line| print lineendfile.close #读取完文件后要将通道关闭,不然会造成IO堵塞# 2.2 File.open方法中使用块时,在块内部处理完并跳出方法之前文件会自动关闭,这个也是块给我们做的File.open("sample.txt") do |file| file.each_line do |line| print line endend# 2.3上面的代码类似于下面的代码file = File.open("sample.txt")begin file.each_line do |line| print line endensure file.closeend# 3.1可以替换部分算法# 使用默认sort方法时没有指定块的时候默认用<=>进行比较str = %w(This is test about block)p str.sort#两者效果相同p str.sort{|a, b| a <=> b}#可以通过块来自定义排序p str.sort{|a, b| a.length <=> b.length}# 使用sort_by时候先将所有的元素使用length 然后再排序 这样不像上面每调用一次块要执行两次length方法p str.sort_by{|item| item.length <=> item.length}# 4.1 定义带块的方法#使用yield 没有带参数def foo a = 1 yield aendfoo {|x| puts x + 2}#带参数def foo2 b a = 2 * b yield aendfoo2(2){|x| puts x}#使用 & 和 call 以参数的形式使用块def bar(&block) a = 3 block.call aendbar{|x| puts x**2}#如果有多个参数的时候 &block 这种类型的参数称为Proc参数# ruby会把传进来的&block 块封装成Proc对象 这样使用call方法的时候就#相当于对象调用方法def bar2(a, b, &block) block.call(a, b)endbar2(2,'x'){|c, d| puts [c, d]}# 控制块的执行# 首先要明确一点break 终止最内部的循环。如果在块内调用,则终止相关块的方法(方法返回 nil)arry = %w(test hahah in ruby)def test_break arry i = 1 arry.each do |str| print [i, str] break if i == 3 i += 1 end print '测试普通break'endtest_break arry #break终止循环但还是会执行 print '最后再输出一次'# 下面测试下break在代码块中def test_break2 arry i = 1 arry.each do |str| puts str yield i i += 1 end print '测试在block中break'end#break在块内则终止相关块的方法 并且可以选择返回参数 此处返回0p test_break2(arry){|x| break 0 if x == 3}# next跳到循环的下一个迭代。如果在块内调用,则终止块的执行(yield 表达式返回 nil)。ary = %w(i l x c b d next)def test_next arry i = 1 arry.each do |x| i += 1 next if i == 2 print i,x end print '我是来测是next的'endtest_next aryputs ">>>>>>>>>>>>>>>>>"def test_next2 arry i = 1 arry.each do |x| p yield i, x i += 1 end print '测试块内的next'end#此处当i=2 时候终止块的执行 就是此次yield的返回值为自定义 但 yield下面的i += 1继续执行test_next2(ary) do |a, b| next "test success" if a == 2 print a,bend# 在块中的return 不是return出代码块 而是return出包含这个代码块的方法# 重点因为block是代码的集合不是方法def test_return i = 3 yield i print '方法的return'endtest_return do |x| print "我是块中的return 我要return出去了" return if x == 3end# 块变量可以多重赋值def block_args_test yield() yield(1, 2) yield(1, 2, 3)end#通过一个变量来接收block_args_test{|a| p [a]}#通过三个变量来接收block_args_test{|a, b, c| p [a,b,c]}#通过|*a|来接受 将所有块变量整合成数组来接收block_args_test{|*a| p a}# 将块封装成对象# 上面我们说过了可以按一下方式将块做为参数# 因为&参数名 ruby会自动传进来的块封装成Proc对象 称为Proc参数# 然后通过调用对象的call 来执行代码块的内容def foo(&block) block.callendfoo{puts '测试一下'}#定义一个Proc对象 并调用#两个方法一个是 Proc.newhello = Proc.new do |name| puts "hello i am #{name}"endhello.call('ruby')#proc方法指定块hello2 = proc do |x| print "hello i am #{x}"endhello2.call('Java')#Proc参数一定要放在参数列表的最后一位def call_each(arry, &block) arry.each(&block)endcall_each(1..4){|n| puts n**2}# Proc 是能让块做为对象在程序中使用的类proc = Proc.new {|x| x * 2}p proc.classp proc.call(5)lambda = lambda {|x| x * 2}p lambda.class #也是proc类#为何Porc有两个对象 proc和lambda 区别在何处# 一个中心思想 两大区别# 都是Proc的实例# 但proc的行为更像block lambda的行为更像方法# 区别一 调用时的参数 个数p p = Proc.new {|x, y| p x,y}p p.call(1)p p.call(1, 2)p p.call(1, 2, 3)l = lambda {|x,y| p x, y}# l.call(1) #会报错p l.call(1, 2)# p l.call(1, 2, 3) 也会报错#因为在定义method时候你定义几个变量就传入几个变量 传多传少都会报错#但block 但如果参数少就nil 补全 多的话就无视# 区别2p = Proc.new {|x| return if x > 0}p p.call(1) #会报错因为此block没有被方法包围 所以无法return出方法l = lambda {|x| return if x > 0}p l.call(1) #但lambda就可以被return 因为他的行为更像method#有些对象有to_proc方法 如果对象以"&对象"的形式传递参数# 对象.to_proc就会自动被调用 进而生成Proc对象# 其中符号 Symbol.to_proc方法比较典型# & 把符号 :capitalize 生成Pro对象# Proc.new do |arg|# arg.capitalize# endp arr = %w(a b c)arr.map(&:capitalize)#使用符号来代替方法p "a".capitalize#method => proc => 利用& 才转成blockp arr.map {|x| x.capitalize }#附上map each的区别# each:连续遍历集合中的所有元素,并做相应的操作,原集合本身不会发生变化。# map: 从集合中获取每个元素,并且传递给块,结果会返回新的数组,原集合发生变化# collect: 类似于map# inject:遍历整个集合,并且将集合中的元素,按照一定的方式累计,最后返回一个新的元素,原集合本省不会发生变化。