# Ruby Block
## 特色
1. 一段不會被主動執行的程式碼
2. 無法單獨存活,被物件話後就可以
## 寫法
do .. end 和 {} 兩種寫法
```ruby=
5.times do |i|
puts i
end
```
```ruby=
5.times { |i|
puts i
}
```
## yeild
### 將控制權轉讓給Block
一般執行程式的狀態 (執行順序 #(順序))
```ruby=
def say_hello #2
puts "hi, 你好!" #3
end
say_hello #1 #4
puts "there!" #5
```
```
hi, 你好!
there!
```
Block就像寄生蟲一樣,依附在方法後的block不會直接被執行,要看宿主要不要讓你執行
以下加上block的狀況
```ruby=
def say_hello
puts "hi, 你好!"
end
say_hello {
puts "here!" #依附在方法後的block
}
puts "there!"
```
```
hi, 你好!
there!
```
要讓其能被執行要靠 **yeild** 的方法
```ruby=
def say_hello #2
puts "hi, 你好!" #3
yield
puts "hi, 大家好!"#5
end
#1 #6
say_hello {
puts "here!" #4
}
puts "there!" #7
```
```
hi, 你好!
here!
hi, 大家好!
there!
```
### 轉移時附加value
控制權轉移的同時,可以附加value送出(可以不只一個)
```ruby=
def say_hello
yield 3, 5 #這邊的3會被引入到下方的參數n
end
say_hello{ |n ,m|
puts n #3
puts m #5
}
```
當完成之後會自動回傳block最後一行的執行結果,在block裡不使用return
```ruby=
def test_two #2
if yield 2 #3 #5
puts "yes" #6
else
puts "no"
end
end
#1
test_two{ |n|
n == 2 #4 return true
}
#yes
```
應用 : 找到1~100的奇數
```ruby=
p(1..100).select {|n| n.odd?}
```
練習 : 找出陣列中的奇數
```ruby=
def my_select(list)
result = []
list.each do |n|
result << n if yield(n)
end
result
end
p my_select([1,2,3,4,5]) {|i| i.odd?}
p (1..100).select {|n| n.odd?}
```
ruby有倒裝的寫法
```ruby=
if x > 0
puts "hello"
end
```
可以寫成
```ruby=
puts "hello" if x > 0
```
的倒裝句寫法,所以:
```ruby=
result << n if yield n
```
其實等於:
```ruby=
if yield n
result << n
end
```
## Block 不是參數
如果沒有Block,但卻yield的話,會發生local jump error的錯誤訊息,因為yield不知道要執行哪個Block
```ruby=
def say_hello
yield
end
say_hello
```
Block不是參數,所以要知道Block存不存在要用 **block_given?** 檢查Block是否存在
```ruby=
def say_hello
yield if block_given?
end
say_hello #沒有Block不會執行
say_hello{
puts "hi" #block_given 為 true 所以執行 "hi"
}
```
:::info
不同Block 大括號 vs do ... end 的差異
```ruby=
list = [1,2,3,4,5]
p list.map {|item|
# {}結合率比較強,所以再執行的過程中會先執行Block
item * 2
}
p list.map do |item|
# do ... end 結合率比較弱,所以結合率被p 搶走
item * 2
end
```
{} 的結果 [2, 4, 6, 8, 10]
do .. end 的結果 #<Enumerator: [1, 2, 3, 4, 5]:map>
:::
### 物件化 Block
將 block 物件化後,透過給予引數來執行,物件化的方式有下面幾種
```ruby=
add_two = Proc.new {|n| n+2} #方法一
p add_two.call(3) #比較常用call
p add_two[3]
p add_two.(3)
p add_two.===(3)
add_two2 = lambda {|a| a + 2} #方法二 (lambda)
p add_two2.call(3)
add_two3 = -> (x) { x + 2 } #方法三 (lambda)
p add_two3.call(3)
```
Proc vs Lambda
Proc 多給引數不會發生錯誤,Lambda會發生錯誤
```ruby=
add_two = Proc.new {|n| n+2}
p add_two.call(1,2,3) # 印出3
add_two2 = lambda {|a| a+2}
p add_two2.call(1,2,3) #跳error
```