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:遍歷整個集合,而且將集合中的元素,按照必定的方式累計,最後返回一個新的元素,原集合本省不會發生變化。
相關文章
相關標籤/搜索