Ruby 中关于block的一些总结

 在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 line
end
file.close #读取完文件后要将通道关闭,否则会形成IO堵塞

# 2.2 File.open方法中使用块时,在块内部处理完并跳出方法以前文件会自动关闭,这个也是块给咱们作的
File.open("sample.txt") do |file|
  file.each_line do |line|
    print line
  end
end

# 2.3上面的代码相似于下面的代码
file = File.open("sample.txt")
begin
  file.each_line do |line|
      print line
  end
ensure
  file.close
end

# 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 a
end

foo {|x| puts x + 2}

#带参数
def foo2 b
  a = 2 * b
  yield a
end

foo2(2){|x| puts x}

#使用 & 和 call 以参数的形式使用块
def bar(&block)
  a = 3
  block.call a
end

bar{|x| puts x**2}

#若是有多个参数的时候 &block 这种类型的参数称为Proc参数
# ruby会把传进来的&block 块封装成Proc对象 这样使用call方法的时候就
#至关于对象调用方法

def bar2(a, b, &block)
  block.call(a, b)
end

bar2(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'
end

test_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在块内则终止相关块的方法 而且能够选择返回参数 此处返回0
p 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的'
end

test_next ary

puts ">>>>>>>>>>>>>>>>>"

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,b
end

# 在块中的return 不是return出代码块 而是return出包含这个代码块的方法
# 重点由于block是代码的集合不是方法
def test_return
  i = 3
  yield i
  print '方法的return'
end

test_return do |x|
  print "我是块中的return 我要return出去了"
  return if x == 3
end

# 块变量能够多重赋值
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.call
end

foo{puts '测试一下'}

#定义一个Proc对象 并调用
#两个方法一个是 Proc.new
hello = Proc.new do |name|
  puts "hello i am #{name}"
end

hello.call('ruby')

#proc方法指定块
hello2 = proc do |x|
  print "hello i am #{x}"
end

hello2.call('Java')

#Proc参数必定要放在参数列表的最后一位
def call_each(arry, &block)
  arry.each(&block)
end

call_each(1..4){|n| puts n**2}

# Proc 是能让块作为对象在程序中使用的类
proc = Proc.new {|x| x * 2}
p proc.class
p 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 补全 多的话就无视

# 区别2
p = 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
# end
p arr = %w(a b c)
arr.map(&:capitalize)
#使用符号来代替方法
p "a".capitalize
#method => proc => 利用& 才转成block
p arr.map {|x| x.capitalize }

#附上map each的区别
# each:连续遍历集合中的全部元素,并作相应的操做,原集合自己不会发生变化。
# map: 从集合中获取每一个元素,而且传递给块,结果会返回新的数组,原集合发生变化
# collect: 相似于map
# inject:遍历整个集合,而且将集合中的元素,按照必定的方式累计,最后返回一个新的元素,原集合本省不会发生变化。
相关文章
相关标签/搜索