Swift Functions 的兩三事

Swift 的 functions 可以有很多種寫法,非常彈性,支援參數標籤、預設參數、不限參數數量、in-out 跟多載

// 最一般的寫法
func fooBar() -> String {
    return "foo bar"
}

// 甚至可以不寫 return
func fooBar() -> String {
    "foo bar"
}

參數標籤

參數前面都可以自訂標籤,在呼叫的該 func 時,xcode 會自動帶出前述標籤,如果想省略也可改為 _ 底線

// 參數標籤可以自定義
func fooBar(with params: Int) { }
fooBar(label: 1)

// 省略標籤
func fooBar(_ params: Int) { }
fooBar(1)

預設參數值

可在 func 的參數設定預設值,在呼叫時就可省略不寫

func fooBar(with params: Int = 1) { }
fooBar()

不限數量的參數 (Variadic)

如果需要用到一串很長且重複類型的參數也可以這樣寫 e.g., Int..., Double..., String...

func fooBar(with params: Int...) {
    print("params: \(params)")
}
fooBar(label: 1,2,3,4)
// params: [1, 2, 3, 4]

In-Out 參數

在參數前面加上 inout 這個修飾表示,就可以在函式內部改變參數值同時作用到傳入的變數,調用時,參數前面要加上 &

func swap(_ a: inout Int, _ b: inout Int) {
    let tmp = a
    a = b
    b = tmp
}
var a = 1, b = 2
swap(&a, &b)
print("\(a), \(b)") // 2, 1

函數型別

函數可以當作變數(variable)使用

func square(_ a: Int) -> Int {
    return a * a
}
var mySquare: (Int) = square(2)

函數也可以當作參數使用,只要參數是相同的型別即可

// myfunc 可帶入 square 的 func 因為類型相同
func doMath(_ myfunc: (Int) -> Int, _ a: Int) {
    print("result: \(square(a))")
}
doMath(square, 3) // 9

函數還可以當作回傳型別使用,也可寫成巢狀式函數 (Nested functions)

func fooBar(flag: Bool) -> (Int) -> Int {
    func foo(_ a: Int) -> Int { a * 2 }
    func bar(_ a: Int) -> Int { a / 2 }
    return flag ? foo : bar
}
// 測試看看
var a = 2
let myFooBar = fooBar(flag: a < 8)
while a < 8 {
    print("\(a)")
    a = myFooBar(a)
}
// 2
// 4

var a = 16
let myFooBar = fooBar(flag: a < 8)
while a > 2 {
    print("\(a)")
    a = myFooBar(a)
}
// 16
// 8
// 4

Overloading

Swift 函數支援多載的使用方式:

  1. 同名稱,但回傳型別不同
  2. 同名稱,但參數型別不同
  3. 同名稱,參數標籤不同
  4. 同名稱,參數數量不同
struct MyStruct {
    // 同名稱,但回傳型別不同
    func foo() -> String { "" }
    func foo() -> Int { 1 }
    
    // 同名稱,但參數型別不同
    func foo(with a: Int) { }
    func foo(with a: Double) { }
    
    // 同名稱,參數標籤不同,這邊使用 and 標籤
    func foo(and a: Int) { }
    
    // 同名稱,參數數量不同
    func foo(with a: Int, b: Int) { }
}

不過如果是定義在繼承 objc 的物件內的話就無法編譯,因為 objc 的 method 不支援多載

class MyClass: XCTestCase {
    // 錯誤寫法
    func foo(_ a: Int) -> Int { 1 }
    func foo(_ a: Int) -> String { "" }
}
// compiler error
// Method 'foo' with Objective-C selector 'foo:' conflicts with previous declaration with the same Objective-C selector

Reference

comments powered by Disqus