Block

  • 一段不會被主動執行的程式碼 , 有do…end 與 { } 兩種寫法

do … end

  • 常在多行指令使用 ```ruby= p [*1..5].map do | i | i * 2 end

=>

>  因為優先順序較低,所以變成先跟 p 結合了。 
  
> `p([*1..5].map)`
>  造成後面附掛的 Block 就不會被處理了。


- 如果將被省略的小括號還原即可
```ruby= 
p ([*1..5].map do |i| i * 2 end)

大括號 { }

  • 結合率較強
  • 單行較常使用 { } ```ruby= p [*1..5].map { |i| i * 2 }

=> [2, 4, 6, 8, 10]

> 造成差異的原因:有點像是數學的「先乘除後加減」的規則,大括號的優先順序較高

```ruby=
p [*1..5].map { |i| i * 2 }

=> [2, 4, 6, 8, 10]

#還原省略的小括號
p ([*1..5].map { |i| i * 2 })

=> [2, 4, 6, 8, 10]

沒有block狀態時

def say_hello
  puts "hello, 你好"
end


  say_hello  

  puts "here!"
  
  1. say_hello被呼叫

  2. 會去找”say_hello”這個方法,並印出hello, 你好

  3. 回到say_hello

  4. 印出here !

yield

  • 把控制權”轉讓”給block ```ruby= def say_hello puts “hello, 你好” yield puts “hello, 大家好” end

say_hello { puts “here!” }

puts “there!”

=> hello, 你好 here! hello, 大家好 there!


>1. say_hello被呼叫,但block裡還不會被執行。

>2. 會去找“say_hello”這個方法,並印出“hello, 你好”

>3. 印出後底下有yield,但底下印出的值還不會被執行,會先回到最初被呼叫的say_hello,並印出block裡的"here!"

>4. 回到被轉讓的yield,並印出“hello, 大家好”

>5. 最後印出”there“

# 如果只有yield,但後面沒有block的話

- 會出現"localjumperror"
- block並不是參數,如果要判斷block,可用"block_given?"這個方法檢查該block是否存在
 
```ruby=
def say_hello
  if block_given?
    yield
  end
end

  say_hello
  
  
=> nil  

得到nil,因為say_hello裡並沒有block,意即:如果block存在,則yield

def say_hello
  if block_given?
    yield
  end
end

  say_hello {
    puts "123"
  }
  
  
  => 123

此為有block情況,會得到123

yield也可以接參數

  • 可以想像yield為佔位符,並以”書本”佔位,這裡書本意指後方所帶的參數block為執行符。
def say_hello
  puts "開始"
  yield 123         
  puts "結束"
end

say_hello { |x|     
  puts "這裡是 Block,我收到了 #{x}"
}


=> 這裡是Block , 我收到了123

yield以123先佔位,並將123傳給了底下的block

將佔位的123傳入block的變數x內

def say_hello(&abc)
  puts "開始"
    abc.call(123)
  puts "結束"
end

say_hello {|x|
puts "這裡是Block, 我收到了#{x}"


=> 這裡是Block , 我收到了123

與前面使用yield會是同樣意思

在這裡的”&“是將block轉成proc的意思,不然無法把block傳進方法裡

將block物件化

  • 雖然block無法單獨存活,但如果被”物件化”之後就可以了。
  • 呼叫方法時後面的{ | | }符號,其中在 | | 之間放置參數列宣告,若無參數則可省略。

proc 與 lambda(λ)

類別 : Proc

  • 是程序物件,跟block一樣可放入程式區塊可儲存變數,可帶參數在Proc裡return其他值,會離開此物件的方法。
  • 使用new方法產生新的程序物件,並以call方法呼叫程序物件。
  • 因為是類別,所以在使用時首字需“大寫”。
Proc.new { | i | i * 2 }
def proc_coding
  Proc.new
end

proc = proc_coding { "I love coding!" }
p proc.call


=> "I love coding!"
my_proc = Proc.new { return 1 }
puts "Proc result: #{my_proc.call}"


=> unexpected return


帶入return無法被執行
因為Proc只會回傳目前階層的內容

lambda(λ)

  • lambda 或 -> { }
  • lambda為匿名方法和Proc類似,但更加接近method方法。
  • 嚴格檢查參數數目在lambda裡return其他值,會回來繼續執行完方法。
lambda { | i | i * 2 }

-> i { i * 2 }
my_lambda = -> { return 1 }
puts "Lambda result: #{my_lambda.call}"

=> Lambda result: 1


帶入return可被執行
因為lamda會以匿名方法一樣,整個走完方法裡面該回傳的值。