1. 函數的參數與返回值
1.1 多重返回值函數
你可以用元組(tuple)類型讓多個值作為一個復合值從函數中返 回。
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return(currentMin, currentMax)
}
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// 輸出 "min is -6 and max is 109"
1.2 可選元組返回類型
如果函數返回的元組類型有可能整個元組都“沒有值”,你可以使用可選的(optional
)元組返回類型反映整個元組可以是nil
的事實。
注意:
可選元組類型如(Int, Int)?
與元組包含的可選類型如(Int?, Int?)
是不同的。可選的元祖類型,整個元組是可選的,而不只是元組中的每個元素值。
前面的minMax(array:)
函數沒有對傳入的數組進行任何安全檢查,如果array
是個空數組,會觸發一個運行時錯誤,使用可選元組返回類型,可以安全地處理這個問題。
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty {
return nil
}
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return(currentMin, currentMax)
}
你可以使用可選綁定來檢查minMax(array:)
函數返回的是一個存在的元組還是nil
:
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// 輸出 "min is -6 and max is 109"
2.函數參數標簽和參數名稱
2.1 指定參數標簽
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)"
}
from
就是參數標簽,hometown
則是參數名稱。
如果你希望忽略某個參數標簽,可以使用_
來代替一個標簽。
2.2 默認參數值
func greet(person: String, from hometown: String = "Dream") -> String {
return "Hello \(person)! Glad you could visit from \(hometown)"
}
greet(person: "John")
// 輸出 "Hello John! Glad you could visit from Dream"
2.3 可變參數
一個可變參數可以接受零個或多個值,通過在變量類型名后面加入(...
)的方式來定義可變參數。
可變參數的傳入值在函數體中變為此類型的一個數組。
下面這個函數用來計算一組任意長度數字的算術平均數:
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// 返回 3.0
注意:
一個函數最多只能擁有一個可變參數
2.4 輸入輸出參數
函數參數默認是常量,試圖在函數體中更改參數值將會導致編譯錯誤。如果你想要一個函數可以修改參數的值,并且想要在這些修改在函數調用結束后仍然存在,那么就應該把這個參數定義為輸入輸出參數。
定義一個輸入輸出參數時,在參數定義前加inout
關鍵字。一個輸入輸出參數有傳入函數的值,這個值被函數修改,然后被傳出函數,替換原來的值。
你只能傳遞變量給輸入輸出參數,常量或者字面量是不能被修改的。當傳入的參數作為輸入輸出參數時,需要在參數名前加&
符,表示這個值可以被函數修改。
注意:
輸入輸出參數不能有默認值,而且可變參數不能用inout
標記。
func swapTowInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTowInts(&someInt, &anotherInt)
print("someInt is now \(someInt), anotherInt is now \(anotherInt)")
// 輸出 "someInt is now 107, anotherInt is now 3\n"
注意:
輸入輸出參數和返回值是不一樣的。上面的swapTwoInts
函數并沒有定義任何返回值,但是仍然修改了someInt
和anotherInt
的值。輸入輸出參數是函數對函數體外產生影響的另一種方式。
3.函數類型
每個函數都有特定的函數類型,函數的類型由函數的參數類型和返回類型組成。
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multipyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
上面這兩個函數的類型是(Int, Int) -> Int
,可以解讀為“這個函數類型有兩個Int
型參數并返回一個Int
型的值”。
func printHelloWordl() {
print("Hello world!")
}
上面這個函數的類型是:() -> Void
,或者叫做“沒有參數,并返回Void
類型的函數“。
3.1 使用函數類型
在Swift中,使用函數類型就像使用其他類型一樣。例如,你可以定義一個類型為函數的常量或變量,并將適當的函數賦值給它:
var mathFunction:(Int ,Int) -> Int = addTwoInts
這段代碼可以被解讀為:“定義一個叫做mathFunciton
的變量,類型是‘一個有兩個Int
型的參數并返回一個Int
型的值的函數‘,并讓這個新變量指向addTwoInts
函數”。
print("Result: \(mathFunction(2, 3))")
// 輸出 "Result: 5\n"
有相同匹配類型的不同函數可以被賦值給同一個變量:
mathFunction = multipyTwoInts
print("Result: \(mathFunction(2, 3))")
// 輸出 "Result: 6\n"
就像其他類型一樣,當賦值一個函數給常量或變量時,你可以讓Swift來推斷其函數類型:
let anotherMathFunction = addTwoInts
print("\(anotherMathFunction(1, 2))")
// 輸出 "3\n"
3.2 函數類型作為參數類型
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// 打印 "Result: 8\n"
3.3 函數類型作為返回類型
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero 現在指向 stepBackward()
print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero")
// 3...
// 2...
// 1...
// zero!
3.4 嵌套函數
目前為止你見到的所有函數都是全局函數,你也可以把函數定義在別的函數體中,稱作嵌套函數。
默認情況下,嵌套函數對外是不可見的,但是可以被它們的外圍函數調用。一個外圍函數也可以返回它的某一個嵌套函數,使得這個函數可以在其他域中被使用。
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!