本頁包含內(nèi)容:
- 函數(shù)定義與調(diào)用
- 函數(shù)參數(shù)與返回值
- 函數(shù)參數(shù)標(biāo)簽和參數(shù)名稱
- 函數(shù)類型
- 嵌套函數(shù)
** 1、函數(shù)定義與調(diào)用**
當(dāng)你定義一個(gè)函數(shù)時(shí)晶通,你可以定義一個(gè)或多個(gè)有名字和類型的值璃氢,作為函數(shù)的輸入,稱為參數(shù)狮辽,也可以定義某種類型的值作為函數(shù)執(zhí)行結(jié)束時(shí)的輸出一也,稱為返回類型。每個(gè)函數(shù)有個(gè)函數(shù)名隘竭,用來描述函數(shù)執(zhí)行的任務(wù)塘秦。要使用一個(gè)函數(shù)時(shí),用函數(shù)名來“調(diào)用”這個(gè)函數(shù)动看,并傳給它匹配的輸入值(稱作實(shí)參)尊剔。函數(shù)的實(shí)參必須與函數(shù)參數(shù)表里參數(shù)的順序一致。
下面例子中的函數(shù)的名字是 greet(person:) 菱皆,之所以叫這個(gè)名字,是因?yàn)檫@個(gè)函數(shù)用一個(gè)人的名字當(dāng)做輸入须误,并返回向這個(gè)人問候的語句挨稿。為了完成這個(gè)任務(wù),你需要定義一個(gè)輸入?yún)?shù)——一個(gè)叫做 person 的 String 值京痢,和一個(gè)包含給這個(gè)人問候語的 String 類型的返回值:
<pre>func greet(person:String) -> String {
let greating = "Hello," + person + "!"
return greating;
}</pre>
函數(shù)調(diào)用:
<pre>let msg = greet(person: "Anna")
print(msg)
func greetAgain(person: String) -> String {
return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// 打印 "Hello again, Anna!"</pre>
2奶甘、 函數(shù)參數(shù)與返回值
- 無參數(shù)函數(shù)
<pre> func sayHelloWorld() -> String {
return "hello, world"
}
let say = sayHelloWorld()
print(say)
// 打印 "hello, world"</pre>
- 多參數(shù)函數(shù)(嵌套)
<pre> func greetting(person:String, alreadyGreated: Bool) -> String {
if alreadyGreated {
return greetAgain(person: person)
}else {
return greet(person: person)
}
}
let hello = greetting(person: "Tim", alreadyGreated: true)
print(hello)
// 打印 " Hello again, Tim! "</pre>
-
無返回值函數(shù)
func greet1(person: String) {
print("Hello, (person)!")
}
greet1(person: "Dave")
// 打印 "Hello, Dave!"注:因?yàn)檫@個(gè)函數(shù)不需要返回值,所以這個(gè)函數(shù)的定義中沒有返回箭頭"->"和返回類型祭椰。
被調(diào)用時(shí)臭家,一個(gè)函數(shù)的返回值可以被忽略:
func printAndCount(string: String) -> Int {
print(string)
return string.characters.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
let count = printAndCount(string: "hello, world")
print(count)
// 打印 "hello, world" 并且返回值 12
printWithoutCounting(string: "hello, world")
// 打印 "hello, world" 但是沒有返回任何值
-
多重返回值函數(shù)
你可以用元組(tuple)類型讓多個(gè)值作為一個(gè)復(fù)合值從函數(shù)中返回。
下例中定義了一個(gè)名為 minMax(array:) 的函數(shù)方淤,作用是在一個(gè) Int 類型的數(shù)組中找出最小值與最大值钉赁。
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"
-
可選元組返回類型
// 如果函數(shù)返回的元組類型有可能整個(gè)元組都“沒有值”,你可以使用可選的( optional ) 元組返回類型反映整個(gè)元組可以是nil的事實(shí)携茂。你可以通過在元組類型的右括號(hào)后放置一個(gè)問號(hào)來定義一個(gè)可選元組你踩,例如 (Int, Int)? 或 (String, Int, Bool)?
為了安全地處理這個(gè)“空數(shù)組”問題,將 minMax(array:) 函數(shù)改寫為使用可選元組返回類型讳苦,并且當(dāng)數(shù)組為空時(shí)返回 nil :
<pre>func minAndMax(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)
}if let bounds1 = minAndMax(array: [8, -6, 2, 109, 3, 71]) {
print("min is (bounds1.min) and max is (bounds1.max)")
}
// 打印 "min is -6 and max is 109" </pre>
3带膜、函數(shù)參數(shù)標(biāo)簽和參數(shù)名稱
每個(gè)函數(shù)參數(shù)都有一個(gè)參數(shù)標(biāo)簽( argument label )以及一個(gè)參數(shù)名稱( parameter name )。
參數(shù)標(biāo)簽在調(diào)用函數(shù)的時(shí)候使用,調(diào)用的時(shí)候需要將函數(shù)的參數(shù)標(biāo)簽寫在對應(yīng)的參數(shù)前面鸳谜。
參數(shù)名稱在函數(shù)的實(shí)現(xiàn)中使用膝藕。默認(rèn)情況下,函數(shù)參數(shù)使用參數(shù)名稱來作為它們的參數(shù)標(biāo)簽卿堂。
func someFunction(firstParameterName: Int, secondParameterName: Int) {
// 在函數(shù)體內(nèi)束莫,firstParameterName 和 secondParameterName 代表參數(shù)中的第一個(gè)和第二個(gè)參數(shù)值
}
someFunction(firstParameterName: 1, secondParameterName: 2)
所有的參數(shù)都必須有一個(gè)獨(dú)一無二的名字懒棉。雖然多個(gè)參數(shù)擁有同樣的參數(shù)標(biāo)簽是可能的草描,但是一個(gè)唯一的函數(shù)標(biāo)簽?zāi)軌蚴鼓愕拇a更具可讀性。
-
指定參數(shù)標(biāo)簽
你可以在函數(shù)名稱前指定它的參數(shù)標(biāo)簽策严,中間以空格分隔:func someFunction1(argumentLabel parameterName: Int) { // 在函數(shù)體內(nèi)穗慕,parameterName 代表參數(shù)值 }
這個(gè)版本的 greet(person:) 函數(shù),接收一個(gè)人的名字和他的家鄉(xiāng)妻导,并且返回一句問候:
func greetA(person name: String, from hometown: String) -> String {
return "Hello \(name)! Glad you could visit from \(hometown)."
}
print(greetA(person: "Bill", from: "Cupertino"))
// 打印 "Hello Bill! Glad you could visit from Cupertino."
參數(shù)標(biāo)簽的使用能夠讓一個(gè)函數(shù)在調(diào)用時(shí)更有表達(dá)力逛绵,更類似自然語言,并且仍保持了函數(shù)內(nèi)部的可讀性以及清 晰的意圖倔韭。
- 忽略參數(shù)標(biāo)簽
如果你不希望為某個(gè)參數(shù)添加一個(gè)標(biāo)簽术浪,可以使用一個(gè)下劃線( _ )來代替一個(gè)明確的參數(shù)標(biāo)簽。
<pre>func someFunction2(_ firstParameterName: Int, secondParameterName: Int) {
// 在函數(shù)體內(nèi)寿酌,firstParameterName 和 secondParameterName 代表參數(shù)中的第一個(gè)和第二個(gè)參數(shù)值
}
someFunction2(1, secondParameterName: 2)</pre>
注: 如果一個(gè)參數(shù)有一個(gè)標(biāo)簽胰苏,那么在調(diào)用的時(shí)候必須使用標(biāo)簽來標(biāo)記這個(gè)參數(shù)。
- 默認(rèn)參數(shù)值
你可以在函數(shù)體中通過給參數(shù)賦值來為任意一個(gè)參數(shù)定義默認(rèn)值(Deafult Value)醇疼。當(dāng)默認(rèn)值被定義后硕并,調(diào)用這 個(gè)函數(shù)時(shí)可以忽略這個(gè)參數(shù)法焰。
func someFunction3(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// 如果你在調(diào)用時(shí)候不傳第二個(gè)參數(shù),parameterWithDefault 會(huì)值為 12 傳入到函數(shù)體中倔毙。
}
someFunction3(parameterWithoutDefault: 3, parameterWithDefault: 6)
// parameterWithDefault = 6
someFunction3(parameterWithoutDefault: 4)
// parameterWithDefault = 12
- 可變參數(shù)
一個(gè)可變參數(shù)(variadic parameter)可以接受零個(gè)或多個(gè)值埃仪。
函數(shù)調(diào)用時(shí),你可以用可變參數(shù)來指定函數(shù)參數(shù)可以被傳入不確定數(shù)量的輸入值陕赃。
通過在變量類型名后面加入( ... )的方式來定義可變參數(shù)卵蛉。
可變參數(shù)的傳入值在函數(shù)體中變?yōu)榇祟愋偷囊粋€(gè)數(shù)組。例如么库,一個(gè)叫做 numbers 的 Double... 型可變參數(shù)毙玻,在函數(shù)體內(nèi)可以當(dāng)做一個(gè)叫 numbers 的 [Double] 型的數(shù)組常量。
下面的這個(gè)函數(shù)用來計(jì)算一組任意長度數(shù)字的算術(shù)平均數(shù)(arithmetic mean):
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
let res1 = arithmeticMean(1, 2, 3, 4, 5)
print(res1)
// 返回 3.0, 是這 5 個(gè)數(shù)的平均數(shù)廊散。
let res2 = arithmeticMean(3, 8.25, 18.75)
print(res2)
// 返回 10.0, 是這 3 個(gè)數(shù)的平均數(shù)桑滩。
注意:一個(gè)函數(shù)最多只能擁有一個(gè)可變參數(shù)。
- 輸入輸出參數(shù)
** 4允睹、 函數(shù)類型**
每個(gè)函數(shù)都有種特定的函數(shù)類型运准,函數(shù)的類型由函數(shù)的參數(shù)類型和返回類型組成。
<pre> func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}</pre>
這個(gè)例子中定義了兩個(gè)簡單的數(shù)學(xué)函數(shù):addTwoInts 和 multiplyTwoInts缭受。這兩個(gè)函數(shù)都接受兩個(gè) Int 值胁澳, 返回一個(gè) Int 值
這兩個(gè)函數(shù)的類型是 (Int, Int) -> Int ,可以解讀為“這個(gè)函數(shù)類型有兩個(gè) Int 型的參數(shù)并返回一個(gè) Int 型的值米者。
下面是另一個(gè)例子韭畸,一個(gè)沒有參數(shù),也沒有返回值的函數(shù):
<pre>func printHelloWorld() {
print("hello, world")
}</pre>
這個(gè)函數(shù)的類型是: () -> Void 蔓搞,或者叫“沒有參數(shù)胰丁,并返回 Void 類型的函數(shù)
- 使用函數(shù)類型
在 Swift 中,使用函數(shù)類型就像使用其他類型一樣喂分。例如锦庸,你可以定義一個(gè)類型為函數(shù)的常量或變量,并將適當(dāng)?shù)暮瘮?shù)賦值給它:
var mathFunction: (Int, Int) -> Int = addTwoInts
print("Result: (mathFunction(2, 3))")
// Prints "Result: 5"
有相同匹配類型的不同函數(shù)可以被賦值給同一個(gè)變量蒲祈,就像非函數(shù)類型的變量一樣:
mathFunction = multiplyTwoInts
print("Result: (mathFunction(2, 3))")
// Prints "Result: 6"
-
函數(shù)類型作為參數(shù)類型
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) { print("Result: \(mathFunction(a, b))") } printMathResult(addTwoInts, 3, 5) // 打印 "Result: 8"
這個(gè)例子定義了 printMathResult(::_:) 函數(shù)甘萧,
它有三個(gè)參數(shù):第一個(gè)參數(shù)叫 mathFunction ,類型是 (Int, Int) -> Int 梆掸,你可以傳入任何這種類型的函數(shù);
第二個(gè)和第三個(gè)參數(shù)叫 a 和 b 扬卷,它們的類型都是 Int ,這兩個(gè)值作為已給出的函數(shù)的輸入值酸钦。
- 函數(shù)類型作為返回類型
你可以用函數(shù)類型作為另一個(gè)函數(shù)的返回類型怪得。你需要做的是在返回箭頭(->)后寫一個(gè)完整的函數(shù)類型。
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
如下名為 chooseStepFunction(backward:) 的函數(shù),它的返回類型是 (Int) -> Int 類型的函數(shù)汇恤。
chooseStepF unction(backward:) 根據(jù)布爾值 backwards 來返回 stepForward(:) 函數(shù)或 stepBackward(:) 函數(shù):
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
你現(xiàn)在可以用 chooseStepFunction(backward:) 來獲得兩個(gè)函數(shù)其中的一個(gè):
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero 現(xiàn)在指向 stepBackward() 函數(shù)庞钢。
上面這個(gè)例子中計(jì)算出從 currentValue 逐漸接近到0是需要向正數(shù)走還是向負(fù)數(shù)走。currentValue 的初始值 是 3 因谎,這意味著 currentValue > 0 為真(true)基括,這將使得 chooseStepFunction(:) 返回 stepBackwar d(:) 函數(shù)。一個(gè)指向返回的函數(shù)的引用保存在了 moveNearerToZero 常量中财岔。
print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!
** 5风皿、嵌套函數(shù)**
到目前為止本章中你所見到的所有函數(shù)都叫全局函數(shù)(global functions),它們定義在全局域中匠璧。你也可以把函數(shù)定義在別的函數(shù)體中桐款,稱作嵌套函數(shù)(nested functions)。
默認(rèn)情況下夷恍,嵌套函數(shù)是對外界不可見的魔眨,但是可以被它們的外圍函數(shù)(enclosing function)調(diào)用。一個(gè)外圍函數(shù)也可以返回它的某一個(gè)嵌套函數(shù)酿雪,使得這個(gè)函數(shù)可以在其他域中被使用遏暴。
你可以用返回嵌套函數(shù)的方式重寫 chooseStepFunction(backward:) 函數(shù):
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)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!