【Swift】#23 關於 Function 與 Closure 的那些小事

Function / Closure

Ethan
11 min readAug 12, 2021

Function

Photo by Alexandre Debiève on Unsplash

Parameter labels

func sayHello(to name: String) {
print("Hello, \(name)!")
}
// 有外部名時,用外部名呼叫
sayHello(to: "Ewen") // Hello, Ewen!
func greet(_ person: String) {
print("Hello, \(person)!")
}
// 用 _ 省略外部名,呼叫就不用寫參數
greet("Ewen") // Hello, Ewen!

Default parameters

func greet(_ person: String, nicely: Bool = true) {
if nicely == true {
print("\(person)\(person)第一名")
} else {
print("\(person)退散")
}
}
greet("戴資穎") // 戴資穎戴資穎第一名
greet("酸民", nicely: false) // 酸民退散

Variadic functions

func square(numbers: Int...) {
for number in numbers {
print("\(number)的平方是\(number * number)")
}
}
square(numbers: 1, 2, 3, 4, 5)
/*
1的平方是1
2的平方是4
3的平方是9
4的平方是16
5的平方是25
*/

Writing throwing functions

enum PasswordError: Error {
case obvious
}
func checkPassword(_ password: String) throws -> Bool {
if password == "password" {
throw PasswordError.obvious
}
return true
}
// 執行 throwing functions
do {
try checkPassword("password")
print("可以用這組密碼")
} catch {
print("不能用\"password\"當密碼")
}
// 不能用"password"當密碼

inout parameters

func doubleInPlace(number: inout Int) {
number *= 2
}
var myNum = 10
doubleInPlace(number: &myNum)
print(myNum) // 20

function 當參數

無參數、無回傳值 function 當作參數

func orderAndDrink(upgrade: () -> Void) {
print("今晚我想來點:")
upgrade()
}
func addIngredient() {
print("厚奶蓋和寒天蒟蒻")
}
orderAndDrink(upgrade: addIngredient)/*
今晚我想來點:
厚奶蓋和寒天蒟蒻
*/

有單一參數、無回傳值 function 當作參數

func orderAndDrink(upgrade: (String) -> Void) {
print("今晚我想來點:")
upgrade("蘋果紅茶")
}
func addIngredient(name: String) -> Void {
print("\(name)加厚奶蓋和寒天蒟蒻")
}

orderAndDrink(upgrade: addIngredient)
/*
今晚我想來點:
蘋果紅茶加厚奶蓋和寒天蒟蒻
*/

有單一參數、有回傳值 function 當作參數

func orderAndDrink(upgrade: (String) -> String){
print("今晚我想來點:")
let message = upgrade("蘋果紅茶")
print(message)
}
func addIngredient(name: String) -> String {
return "\(name)加厚奶蓋和寒天蒟蒻"
}
orderAndDrink(upgrade: addIngredient)
/*
今晚我想來點:
蘋果紅茶加厚奶蓋和寒天蒟蒻
*/

function 回傳 function

// order() 回傳有一個 String 型別參數的 function,該 function 無回傳值func drink(name: String) -> Void {
print("\(name)加厚奶蓋和寒天蒟蒻")
}
func order() -> (String) -> Void {
print("今晚我想來點")
return drink
}
// 法一
let message = order()
message("蘋果紅茶")
// 法二(也可以但不推薦)
let message2: Void = order()("蘋果紅茶")
/*
今晚我想來點:
蘋果紅茶加厚奶蓋和寒天蒟蒻,正常微冰
*/

Nested function Capturing

func add(adjective: String) -> (String) -> String {
var superString = "超級"

func createSentence(name: String) -> String {
let message = superString + adjective + name
superString += "超級"
return message
}

return createSentence
}
let goodMessage = add(adjective: "可愛的")
print(goodMessage("資穎"))
print(goodMessage("資穎"))
let badMessage = add(adjective: "可惡的")
print(badMessage("酸民"))
print(badMessage("酸民"))
/*
超級可愛的資穎
超級超級可愛的資穎
超級可惡的酸民
超級超級可惡的酸民
*/

Closure

Photo by Georg Bommeli on Unsplash

Closure 呼叫

無參數、無回傳值 closure 呼叫

let addIngredient = {
print("加厚奶蓋和寒天蒟蒻")
}
addIngredient() // 加厚奶蓋和寒天蒟蒻

有單一參數、無回傳值 closure 呼叫

let addIngredient = { (name: String) in
print("\(name)加厚奶蓋和寒天蒟蒻")
}
addIngredient("蘋果紅茶") // 蘋果紅茶加厚奶蓋和寒天蒟蒻

有單一參數、有回傳值 closure 呼叫

let addIngredient = { (name: String) -> String in
return "\(name)加厚奶蓋和寒天蒟蒻"
}
let message = addIngredient("蘋果紅茶")
print(message) // 蘋果紅茶加厚奶蓋和寒天蒟蒻

Closure 當參數

無參數、無回傳值 closure 當作參數

func orderAndDrink(upgrade: () -> Void) {
print("今晚我想來點:")
upgrade()
}

// 法一
let addIngredient = {
print("厚奶蓋和寒天蒟蒻")
}

orderAndDrink(upgrade: addIngredient)
// 法二: Trailing closure - 省略代表 closure 的那個參數。之後都用這個語法。
orderAndDrink() {
print("厚奶蓋和寒天蒟蒻")
}
/*
今晚我想來點:
厚奶蓋和寒天蒟蒻
*/

【續】若剩 closure 是參數,可以把呼叫它的的函式的括號省略。

orderAndDrink {
print("厚奶蓋和寒天蒟蒻")
}

有單一參數、無回傳值 closure 當作參數

func orderAndDrink(upgrade: (String) -> Void) {
print("今晚我想來點:")
upgrade("蘋果紅茶")
}
orderAndDrink { (name: String) -> Void in
print("\(name)加厚奶蓋和寒天蒟蒻")
}
/*
今晚我想來點:
蘋果紅茶加厚奶蓋和寒天蒟蒻
*/

有單一參數、有回傳值 closure 當作參數

func orderAndDrink(upgrade: (String) -> String) {
print("今晚我想來點:")
let message = upgrade("蘋果紅茶")
print(message)
}
orderAndDrink {(name: String) -> String in
return "\(name)加厚奶蓋和寒天蒟蒻"
}
/*
今晚我想來點:
蘋果紅茶加厚奶蓋和寒天蒟蒻
*/

・Swift 知道參數型別是 String,可省略。

orderAndDrink { name -> String in
return "\(name)加厚奶蓋和寒天蒟蒻"
}

・Swift 知道回傳值是 String,可省略。

orderAndDrink { name in
return "\(name)加厚奶蓋和寒天蒟蒻"
}

・只有一行,可省略 return。

orderAndDrink { name in
"\(name)加厚奶蓋和寒天蒟蒻"
}

・最後,省略 name in,name 改用 Shorthand parameter names($0, $1 …)

orderAndDrink {
"\($0)加厚奶蓋和寒天蒟蒻"
}

有多參數、有回傳值 closure 當作參數

func orderAndDrink(upgrade: (String, String) -> String) {
print("今晚我想來點:")
let message = upgrade("蘋果紅茶","正常微冰")
print(message)
}
orderAndDrink {
"\($0)加厚奶蓋和寒天蒟蒻,\($1)"
}
/*
今晚我想來點:
蘋果紅茶加厚奶蓋和寒天蒟蒻,正常微冰
*/

function 回傳 Closure

// orderAndDrink() 回傳有一個 String 型別參數的 closure,該 closure 無回傳值func orderAndDrink() -> (String) -> Void {
print("今晚我想來點:")
return {
print("\($0)加厚奶蓋和寒天蒟蒻")
}

}
// 法一
let message = orderAndDrink()
message("蘋果紅茶")
// 法二(也可以但不推薦)
let message2: Void = orderAndDrink()("蘋果紅茶")
/*
今晚我想來點:
蘋果紅茶加厚奶蓋和寒天蒟蒻,正常微冰
*/

Closure capturing

func add(adjective: String) -> (String) -> String {
var superString = "超級"
return {
let message = superString + adjective + $0
superString += "超級"
return message
}

}
let goodMessage = add(adjective: "可愛的")
print(goodMessage("資穎"))
print(goodMessage("資穎"))
let badMessage = add(adjective: "可惡的")
print(badMessage("酸民"))
print(badMessage("酸民"))
/*
超級可愛的資穎
超級超級可愛的資穎
超級可惡的酸民
超級超級可惡的酸民
*/

--

--

Ethan
Ethan

Written by Ethan

Life is what happens to you while you’re busy making other plans.

No responses yet