高見龍

iOS app/Ruby/Rails Developer & Instructor, 喜愛非主流的新玩具 :)

Do..End v.s Braces

話說在Ruby裡,Block可以用do..end的方式來寫,也可以用大括號來寫,例如用do..end的方式寫:

1
2
3
(1..5).each do |i|
  puts i   # 得到1 2 3 4 5
end

用大括號的方式寫的話:

1
2
3
(1..5).each { |i|
  puts i   # 一樣也是得到1 2 3 4 5
}

不過這兩天在看The Ruby Way的時候,看到一段是這樣寫的:

“Note that do and end may be substituted for the braces that delimit a block. There are differences, but they are fairly subtle.”

The Ruby Way(2nd edition) Page.22

書裡沒看到特別講到底哪邊不一樣,所以好奇的到處翻了網路上的一些資料,發現原來這兩種寫法的優先順序有一些些的不一樣,來看一段範例:

1
2
3
4
5
6
7
8
9
my_array = [1, 2, 3, 4, 5]

p my_array.map { |item|
  item * 2  # 得到[2, 4, 6, 8, 10]
}

p my_array.map do |item|
  item * 2  # 得到[1, 2, 3, 4, 5]
end

為什麼結果跟預期的不一樣? 原來,因為省略了一些小括號,第二段的程式碼本來的意思是:

1
p(my_array.map do |item| item * 2 end)  # 得到[2, 4, 6, 8, 10]

但卻因為do..end的優先順序比較小,原式被解析成:

1
p(my_array.map) do |item| item * 2 end # 得到[1, 2, 3, 4, 5]

結果後面的do..end還沒開始跑,my_array.map就先被p給印出來了..而用大括號的寫法的優先順序比較高,則不會有這個困擾。這樣那到底什麼時候要用do..end? 什麼時候要用大括號? 還是乾脆全部都用大括號就好?

基本上如果Block的執行結果是會有回傳值的,那就建議用大括號來寫,其它的大致上都可以用do..end來寫。

果然魔鬼都躲在細節裡!

如果寫得有錯再請不吝指正,感謝!

Comments