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 函數支援多載的使用方式:
- 同名稱,但回傳型別不同
- 同名稱,但參數型別不同
- 同名稱,參數標籤不同
- 同名稱,參數數量不同
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