
每一種語言的閉包 (closure) 概念都不太一樣, Swift 的閉包簡單說是種匿名函數 (anonymous function) ,基本的閉包運算式 (closure expression) 如下圖

例如上個單元提過的 mathFunction() ,其中第一個參數 (parameter) 為函數 (function)
| func mathFunction(f: (Int, Int) -> Int, a: Int, b: Int) { |
| println("The result is \(f(a, b)).") |
| } |
這個需要函數的參數就可以用閉包代入,例如
| mathFunction({(p1: Int, p2: Int) -> Int in |
| return p1 + p2 |
| }, 25, 63) |
此閉包需要 p1 跟 p2 兩個 Int 參數,最後回傳 p1 + p2 ,注意關鍵字 (keyword) in 必須放在回傳值 (return value) 之後。
可以採取簡化的的寫法,例如型態名稱可以省略
| mathFunction({p1, p2 in return p1 + p2}, 26, 63) |
其實 return 也可以省略
| mathFunction({p1, p2 in p1 + p2}, 27, 63) |
或是採用 $0 代表第一個參數, $1 表示第二個參數
| mathFunction({$0 + $1}, 28, 63) |
因為此例是回傳兩個參數相加,更簡單的是用運算子函數 (operator function) ,也就是一個加號
| mathFunction(+, 29, 63) |
以上全部輸入 Playground ,結果如下

其中像是用 $0 、 $1 的方式可以寫在函數呼叫的小括弧後,不過這樣函數參數就要放在參數列的最後一個,例如下面把 mathFunction() 改成 mathFunction2()
| func mathFunction2(a: Int, b: Int, f: (Int, Int) -> Int) { |
| println("The result is \(f(a, b)).") |
| } |
| mathFunction2(30, 63) {$0 + $1} |
輸入到 Playground ,結果如下

這樣的好處是閉包需要寫多行程式碼的時候,例如陣列有個 map() 方法 (method) ,需要一個函數參數
| let d = [ |
| 0: "零", 1: "一", 2: "二", 3: "三", 4: "四", |
| 5: "五", 6: "六", 7: "七", 8: "八", 9: "九"] |
| let n = [32, 85, 101] |
| let s = n.map { |
| (var i) -> String in |
| var output = "" |
| while i > 0 { |
| output = d[i % 10]! + output |
| i /= 10 |
| } |
| return output |
| } |
方法是專屬於物件 (object) 的函數,定義上跟函數極為相似。
上例是把 100 之類的數字換成一零一的國字,留意這一行
| output = d[i % 10]! + output |
因為這裡 d[i % 10]! 從 d 中取出的值會是選擇型態 (optional type) ,加上 ! 才能夠利用該字典 (dictionary) 的值。
輸入 Playground ,結果如下

下個單元繼續討論如何設計型態 (type) ,也就是定義自己的列舉 (enumeration) 、結構 (structure) 與類別 (class) 。
中英文術語對照
| 閉包 | closure |
| 匿名函數 | anonymous function |
| 閉包運算式 | closure expression |
| 參數 | parameter |
| 函數 | function |
| 關鍵字 | keyword |
| 回傳值 | return value |
| 運算子函數 | operator function |
| 方法 | method |
| 物件 | object |
| 選擇型態 | optional type |
| 字典 | dictionary |
| 型態 | type |
| 列舉 | enumeration |
| 結構 | structure |
| 類別 | class |
沒有留言:
張貼留言