---
# System prepended metadata

title: 'Method,Block'

---

# 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]
    ```
