最近寫程式常常遇到closure,每當以為自己快要跟它當好朋友的時候卻又發現,不,我們一點也不熟,只好翻出之前的學習筆記來溫習一下。
這篇來簡單說明function如何簡化成closure。
Function
一般在宣告function時,會有func keyword、function name,也可能會有input parameter、input parameter type、return type。
初學者較少見的是,function的parameter及return type也可以是function。
將Function做為參數
宣告一個function calculator當範例,它能夠執行將兩個parameter相加的運算,並回傳結果。
但假如希望這個calculator的運算規則能夠從相加改成相乘時,必須要回到function中修改return的內容。
為了讓程式更方便、容易維護,這時候我們也可以讓原本的calculator中加入一個function參數,讓呼叫calculator時,由這個傳入calculator的function來決定calculator會執行什麼樣的運算規則。
return的部分則改寫成operation(n1, n2),意即將parameter n1、n2傳入operation function中。
而這個在宣告calculator時,operation的data type則必須與欲傳入的function的格式和參數型別相同。
因為function add有兩個parameter,兩個parameter及return的型別都是Int,所以operation也同樣有兩個parameter與return value,型別也都是Int。
用Closure簡化程式
Closure是沒有名字的function。如果這個要傳入function calculator作為argument的function add不會其他地方被呼叫,則可以將它簡化成closure,不必再額外宣告一個function add。
按照以下步驟,就可以將原本的function add改寫成一個closure,並且傳入function calculator。
func add(no1: Int, no2:Int) -> Int {
return no1 + no2
}
- 刪掉keyword func
- 刪掉程式名字add
- 將第一個大括號{移到最前面
- 在原本大括號的地方加上keyword in
{(no1: Int, no2:Int) -> Int in
return no1 + no2
}
接著在呼叫calculator時,將簡化成closure的那串code丟進calculator的operation做為它的argument。
此時calculator所得到的運算和之前仍然相同。
進一步簡化程式
Swift可以自己偵測到data type,所以可以移除說明closure中parameter型別的Int。Swift也會自己推斷no1 + no2是要回傳的值,因此也可以省略return。
- 省略closure中的參數型別
- 省略closure中的keyword return
Trailing Closure
在Swift中,如果function最後一個parameter是個closure,那麼那個parameter name operation可以被省略,變成trailing closure。
- 省略closure的parameter name operation
- 將小括號)移到closure的大括號{前
沒有名字的parameter:$0、$1
Closure中parameter的名字也可以省略,改成用$0代表是第1個parameter,$1代表第2個parameter。
@escaping
一般做為argument傳入function的function在function執行完畢後就會隨著消失,例如下圖傳入completion的function若沒有加上@escaping就會在func fetchImage執行完畢後跟著消失,但加上了@escaping,就可以讓傳入completion的這個function在func fetchImage執行完畢後仍然繼續存活執行它的功能。
例如搭配URLSession就是需要使用@escaping的常見時機,它讓completion的function在function fetchImage這個執行完畢後還能繼續使用。
Pros and Cons
Closure的優點是可以徹底簡化原本需要撰寫多行的code,但同時也犧牲掉了程式的可讀性,讓對於swift不那麼熟悉的人不容易理解這行code的意義。