# Method,Block
[TOC]
# 程式碼區塊(Block)
- ****Block 不是物件****
作用域??
{}
do ... end
- ****Block 不是參數****
Block 通常得像寄生蟲一樣依附或寄生在其它的方法或物件(或是使用某些類別把它物件化),但它不是參數
- ****如何執行 Block 的內容?****
> 某 Block:「嘿,say_hello_to 方法你好,我要掛在你身上囉」
>
> say_hello_to :「隨便啊,你要掛就讓你掛,但要不要讓你執行是我決定的!」
>
- **yield**
將控制權先交給block(回呼函示??)
```ruby
def say_hello
puts "開始"
yield # 把控制權暫時讓給 Block
puts "結束"
end
say_hello {
puts "這裡是 Block"
}
```
- **傳參數給block**
```ruby
5.times do |i|
puts i # 這個變數 i 只有在 Block 裡有效,會依序印出數字 0 到 4
end
puts i # 離開 Block 之後就失效,出現找不到變數的錯誤(NameError)
```
在使用yield方法把控制權轉讓給block時,順便把值帶給block
```ruby
def say_hello
puts "開始"
yield 123 # 把控制權暫時讓給 Block,並且傳數字 123 給 Block
puts "結束"
end
say_hello { |x| # 這個 x 是來自 yield 方法
puts "這裡是 Block,我收到了 #{x}"
}
```
- ****用 return 回傳 Block 的結果?****
Block 的最後一行執行結果自動會變成 Block 的回傳值,這裡並不是省略了 return,而是不能使用 return 回傳結果。所以如果你在上面那個例子,在 Block 裡試圖用 `return`
回傳結果,像這樣:
```ruby
pick([*1..10]) { |x| return x % 2 == 0 }
```
- **`5.times { ... }` 很好用,但你能自己土砲一個類似的方法嗎?**
```ruby
def my_times(n)
i = 0
while n > i
i += 1
yield i
end
end
my_times(5) { |num|
puts "hello, #{num}xRuby"
}
# 得到結果
# hello, 1xRuby
# hello, 2xRuby
# hello, 3xRuby
# hello, 4xRuby
# hello, 5xRuby
```
- ****大括號跟 do … end 的差別****
```ruby
# 使用 do .. end 寫法
5.times do
puts "哈囉,世界"
end
# 使用大括號寫法
5.times {
puts "哈囉,世界"
}
# 使用大括號一行寫法
5.times { puts "哈囉,世界" }
```
- ****把 Block 物件化****
```ruby
greeting = Proc.new { puts "哈囉,世界" } # 使用 Proc 類別可把 Block 物件化
greeting.call # 印出 "哈囉,世界"
#如果要帶參數
say_hello_to = Proc.new { |name| puts "你好,#{name}"}
say_hello_to.call("尼特羅會長")
```
- ****Proc 呼叫方式****
```ruby
say_hello_to.call("尼特羅會長") # 使用 call 方法
say_hello_to.("尼特羅會長") # 使用小括號(注意,有多一個小數點)
say_hello_to["尼特羅會長"] # 使用中括號
say_hello_to === "尼特羅會長" # 使用三個等號
say_hello_to.yield "尼特羅會長" # 使用 yield 方法
```
# 方法(Method)
- ****定義方法****
使用def
```ruby
def say_hello(name)
puts "hello! #{name}"
end
```
- ****呼叫方法****
```ruby
say_hello('Bob') #=> Hello! Bob
#可視情況省略小
say_hello "Bob"
```
- ****關於方法的冷知識****
定義方法時,Ruby會產生一筆新的Symbol存於記憶體,要調用此方法的話可以使用send,把該筆symbol調用出來
```ruby
send(:say_hello, "Bob")
```
- ****參數預設值****
```ruby
def say_hello(name = 'vint')
puts "hello! #{name}"
end
say_hello() #=> hello! vint
send(:say_hello) #=> hello! vint
```
- ****方法的回傳值****
****puts 不是 return,也沒有回傳值****
```ruby
def bmi_calculator(height, weight)
puts weight / (height / 100.0) ** 2 ####整數除法要注意####
end
bmi_calculator(180, 70)
```
- ****問號跟驚嘆號也是方法的一部份****
通常會使用問號,期望這個方法是會回傳一個布林值,這只是一種慣例
```ruby
puts "".empty? # => true
puts [1, 2, 3, 4, 5].include?(3) # => true
puts "Ruby".start_with?("Ru") # => true
```
驚嘆號表示方法可能會有「副作用」或是「驚喜」
```ruby
#example => reverse會產生一個新的陣列,不會影響原本的陣列
original_list = [1, 2, 3, 4, 5]
reversed_list = original_list.reverse
p reversed_list # => [5, 4, 3, 2, 1]
p original_list # => [1, 2, 3, 4, 5]
#but => reverse加上驚嘆號後,除了回傳新陣列以外也會改變原有陣列
original_list = [1, 2, 3, 4, 5]
reversed_list = original_list.reverse!
p reversed_list # => [5, 4, 3, 2, 1]
p original_list # => [5, 4, 3, 2, 1]
```