函數(shù)是執(zhí)行特定任務(wù)的自包含代碼塊。我們給一個(gè)函數(shù)起一個(gè)名字來標(biāo)識(shí)它做什么,這個(gè)名字在需要的時(shí)候用來“調(diào)用”函數(shù)來執(zhí)行它的任務(wù)。
Swift的統(tǒng)一函數(shù)語法足夠靈活,從沒有參數(shù)名的簡(jiǎn)單C風(fēng)格函數(shù)到每個(gè)參數(shù)都有名稱和參數(shù)標(biāo)簽的復(fù)雜Objective-C風(fēng)格方法唁奢,可以表達(dá)任何東西。參數(shù)可以提供默認(rèn)值來簡(jiǎn)化函數(shù)調(diào)用窝剖,并且參數(shù)可以作為輸入輸出參數(shù)傳遞麻掸,一旦函數(shù)完成其執(zhí)行,這些輸入輸出參數(shù)就會(huì)修改傳遞的變量赐纱。
Swift中的每個(gè)函數(shù)都有一個(gè)類型脊奋,由函數(shù)的參數(shù)類型和返回類型組成熬北。我們可以像Swift中的任何其他類型一樣使用此類型,這樣可以很容易地將函數(shù)作為參數(shù)傳遞給其他函數(shù)诚隙,并從函數(shù)返回函數(shù)讶隐。也可以在其他函數(shù)中編寫函數(shù),將有用的功能封裝在嵌套的函數(shù)范圍內(nèi)久又。
定義和調(diào)用函數(shù)
定義函數(shù)時(shí)巫延,可以選擇定義一個(gè)或多個(gè)命名的類型化值用作函數(shù)的輸入,這個(gè)值稱為參數(shù)地消。我們還可以選擇定義一種值類型炉峰,當(dāng)函數(shù)完成時(shí),它將作為輸出傳回脉执,稱為其返回類型疼阔。
每個(gè)函數(shù)都有一個(gè)函數(shù)名,用于描述函數(shù)執(zhí)行的任務(wù)适瓦。要使用函數(shù)竿开,我們可以用函數(shù)名“調(diào)用”該函數(shù)谱仪,并將與函數(shù)參數(shù)類型匹配的輸入值(稱為參數(shù))傳遞給它玻熙。函數(shù)的參數(shù)必須始終按照與函數(shù)的參數(shù)列表相同的順序提供。
下面示例中的函數(shù)名為greet(person:)
疯攒,它將一個(gè)人的名字作為輸入嗦随,并為該人返回一個(gè)問候語。要實(shí)現(xiàn)這一點(diǎn)敬尺,我們需要定義一個(gè)輸入?yún)?shù)—一個(gè)名為person的String類型的值和一個(gè)返回類型String枚尼,即對(duì)此人的問候語:
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}
所有這些信息都匯總到函數(shù)的定義中,該定義以func關(guān)鍵字作為前綴砂吞。使用返回箭頭->
(一個(gè)連字符后跟一個(gè)右尖括號(hào))表示函數(shù)的返回類型署恍,該箭頭后跟要返回的類型名稱。
這個(gè)定義描述了函數(shù)做什么蜻直,它期望接收什么盯质,以及完成后返回什么。該定義使得從代碼中的其他地方明確地調(diào)用函數(shù)變得容易:
print(greet(person: "Anna"))
// Prints "Hello, Anna!"
print(greet(person: "Brian"))
// Prints "Hello, Brian!"
通過在person參數(shù)標(biāo)簽后面?zhèn)鬟f一個(gè)字符串值來調(diào)用greet(person:)
函數(shù)概而,例如greet(person: "Anna")
呼巷。因?yàn)楹瘮?shù)返回一個(gè)字符串值,所以greet(person:)
可以被包裝在對(duì)print(_:separator:terminator:)
函數(shù)打印該字符串并且可以看到其返回值赎瑰,如上所示王悍。
注意
print(_:separator:terminator:)
函數(shù)的第一個(gè)參數(shù)沒有標(biāo)簽,其他參數(shù)是可選的餐曼,因?yàn)樗鼈冇心J(rèn)值压储。函數(shù)語法的這些變體將在下面的函數(shù)參數(shù)標(biāo)簽鲜漩、參數(shù)名稱和默認(rèn)參數(shù)值中討論。
greet(person:)
函數(shù)的主體首先定義一個(gè)名為greeting的新字符串常量集惋,并將其設(shè)置為簡(jiǎn)單的問候語消息宇整。然后使用return關(guān)鍵字將greeting作為函數(shù)的返回值。在表示return greeting
的代碼行中芋膘,函數(shù)完成其執(zhí)行并返回greeting的當(dāng)前值鳞青。
可以使用不同的輸入值多次調(diào)用greet(person:)
函數(shù)。上面的例子顯示了如果用輸入值“Anna”和輸入值“Brian”調(diào)用它會(huì)發(fā)生什么为朋。函數(shù)在每種情況下都返回一個(gè)定制的問候語臂拓。
要縮短此函數(shù)的正文,可以將消息創(chuàng)建和return語句合并到一行中:
func greetAgain(person: String) -> String {
return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// Prints "Hello again, Anna!"
函數(shù)參數(shù)和返回值
函數(shù)參數(shù)和返回值在Swift中非常靈活习寸。從具有單個(gè)未命名參數(shù)的簡(jiǎn)單實(shí)用的函數(shù)到具有表示性參數(shù)名稱和不同參數(shù)選項(xiàng)的復(fù)雜函數(shù)胶惰,我們可以定義任何內(nèi)容,霞溪。
無參數(shù)函數(shù)
函數(shù)不需要定義輸入?yún)?shù)孵滞。這是一個(gè)沒有輸入?yún)?shù)的函數(shù),每當(dāng)調(diào)用它時(shí)鸯匹,它總是返回相同的字符串消息:
func sayHelloWorld() -> String {
return "hello, world"
}
print(sayHelloWorld())
// Prints "hello, world"
函數(shù)定義仍然需要在函數(shù)名后面加括號(hào)坊饶,即使它不需要任何參數(shù)。調(diào)用函數(shù)時(shí)殴蓬,函數(shù)名后面還會(huì)跟一對(duì)空括號(hào)匿级。
多參數(shù)函數(shù)
函數(shù)可以有多個(gè)輸入?yún)?shù),這些參數(shù)寫在函數(shù)的括號(hào)內(nèi)染厅,用逗號(hào)分隔痘绎。
此函數(shù)將某人的姓名和是否已被問候作為輸入,并為此人返回適當(dāng)?shù)膯柡蛘Z:
func greet(person: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return greetAgain(person: person)
} else {
return greet(person: person)
}
}
print(greet(person: "Tim", alreadyGreeted: true))
// Prints "Hello again, Tim!"
我們通過傳遞用逗號(hào)分隔的一個(gè)標(biāo)記為person的字符串參數(shù)值和一個(gè)標(biāo)記為alreadygreed的Bool參數(shù)值來調(diào)用greet(person:alreadyGreeted:)
函數(shù)肖粮。請(qǐng)注意孤页,此函數(shù)不同于前面一節(jié)中顯示的greet(person:)
函數(shù)。盡管這兩個(gè)函數(shù)的名稱都以greet開頭涩馆,但greet(person:alreadyGreeted:)
函數(shù)接受兩個(gè)參數(shù)行施,但greet(person:)
函數(shù)只接受一個(gè)參數(shù)。
沒有返回值的函數(shù)
函數(shù)不需要定義返回類型凌净。下面是greet(person:)
函數(shù)的一個(gè)版本悲龟,它打印字符串值而不是返回它:
func greet(person: String) {
print("Hello, \(person)!")
}
greet(person: "Dave")
// Prints "Hello, Dave!"
因?yàn)樗恍枰祷刂担院瘮?shù)的定義不包括返回箭頭(->)
或返回類型冰寻。
注意
嚴(yán)格地說须教,這個(gè)版本的greet(person:)
函數(shù)即使沒有定義返回值,仍然返回一個(gè)值。沒有定義返回類型的函數(shù)返回Void類型的特殊值轻腺。這只是一個(gè)空元組乐疆,寫為()
。
調(diào)用函數(shù)時(shí)可以忽略函數(shù)的返回值:
func printAndCount(string: String) -> Int {
print(string)
return string.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting(string: "hello, world")
// prints "hello, world" but doesn't return a value
第一個(gè)函數(shù)printAndCount(string:)
打印一個(gè)字符串贬养,然后將其字符數(shù)返回為Int類型挤土。第二個(gè)函數(shù)printWithoutCounting(string:)
調(diào)用第一個(gè)函數(shù),但忽略其返回值误算。調(diào)用第二個(gè)函數(shù)時(shí)仰美,第一個(gè)函數(shù)仍打印消息,但不使用返回值儿礼。
注意
返回值可以忽略咖杂,但如果表示出會(huì)有返回值的函數(shù)就必須始終有返回值。具有已定義的返回類型的函數(shù)不允許函數(shù)是不返回值的情況蚊夫,嘗試這樣做將導(dǎo)致編譯時(shí)錯(cuò)誤诉字。
具有多個(gè)返回值的函數(shù)
可以使用元組類型作為函數(shù)的返回類型,這樣可以將多個(gè)值作為一個(gè)復(fù)合返回值的一部分來返回知纷。
下面的示例定義了一個(gè)名為minMax(array:)
的函數(shù)壤圃,用于查找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)
}
minMax(array:)
函數(shù)返回一個(gè)包含兩個(gè)Int值的元組。這些值被標(biāo)記為min和max琅轧,以便在查詢函數(shù)的返回值時(shí)可以通過名稱訪問它們伍绳。
minMax(array:)
函數(shù)的主體首先將兩個(gè)局部變量currentMin和currentMax設(shè)置為數(shù)組中第一個(gè)整數(shù)的值。然后鹰晨,該函數(shù)迭代數(shù)組中的剩余值墨叛,并檢查每個(gè)值,看它是否分別小于或大于currentMin和currentMax的值模蜡。最后,最終的最小值和最大值作為兩個(gè)Int值的元組返回扁凛。
由于元組的成員值的名稱是作為函數(shù)返回類型的一部分的忍疾,因此可以使用點(diǎn)語法訪問它們,以檢索找到的最小值和最大值:
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// Prints "min is -6 and max is 109"
請(qǐng)注意谨朝,元組的成員不需要在元組從函數(shù)返回時(shí)命名卤妒,因?yàn)樗鼈兊拿Q已經(jīng)作為函數(shù)返回類型的一部分。
可選元組返回類型
如果從函數(shù)返回的元組類型可能使整個(gè)元組沒有值的話字币,則可以使用可選的元組返回類型來反映整個(gè)元組可以為nil的情況则披。我們可以通過在元組類型的右括號(hào)后面放置問號(hào)來編寫可選的元組返回類型,例如(Int, Int)?
或者(String, Int, Bool)?
洗出。
注意
可選的元組類型士复,例如(Int, Int)?
與包含可選類型的元組,例如(Int?, Int?)
,不同阱洪。對(duì)于可選的tuple類型便贵,整個(gè)元組是可選的,而不僅僅是元組中的每個(gè)值是可選的冗荸。
上面的minMax(array:)
函數(shù)返回一個(gè)包含兩個(gè)Int值的元組承璃。但是,函數(shù)不會(huì)對(duì)它傳遞的數(shù)組執(zhí)行任何安全檢查蚌本。如果array參數(shù)包含空數(shù)組盔粹,則上述minMax(array:)
函數(shù)將在嘗試訪問數(shù)組[0]時(shí)觸發(fā)運(yùn)行時(shí)錯(cuò)誤。
要安全地處理空數(shù)組程癌,請(qǐng)使用可選的元組作為返回類型來編寫minMax(array:)
函數(shù)玻佩,并在數(shù)組為空時(shí)返回nil值:
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:)
函數(shù)是否返回實(shí)際的元組值還是nil:
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// Prints "min is -6 and max is 109"
隱式返回的函數(shù)
如果整個(gè)函數(shù)體是一個(gè)表達(dá)式,則函數(shù)將隱式返回該表達(dá)式席楚。例如咬崔,以下兩個(gè)函數(shù)具有相同的行為:
func greeting(for person: String) -> String {
"Hello, " + person + "!"
}
print(greeting(for: "Dave"))
// Prints "Hello, Dave!"
func anotherGreeting(for person: String) -> String {
return "Hello, " + person + "!"
}
print(anotherGreeting(for: "Dave"))
// Prints "Hello, Dave!"
greeting(for:)
函數(shù)的整個(gè)定義是它返回的問候語消息,這意味著它可以使用這種較短的形式烦秩。anotherGreeting(for:)
函數(shù)使用return關(guān)鍵字返回相同的問候語消息垮斯,就像一個(gè)較長(zhǎng)的函數(shù)一樣。任何只作為一個(gè)返回行編寫的函數(shù)都可以忽略return
關(guān)鍵字只祠。
正如我們將在快捷Getter
聲明中看到的兜蠕,屬性Getter
就可以使用隱式返回。
注意
作為隱式返回值編寫的代碼是必須要返回一些值的抛寝。例如熊杨,不能使用fatalError("Oh no!")
或print(13)
這種不會(huì)返回值的函數(shù)來作為隱式返回值。
函數(shù)參數(shù)標(biāo)簽和參數(shù)名稱
每個(gè)函數(shù)參數(shù)都有一個(gè)參數(shù)標(biāo)簽和一個(gè)參數(shù)名盗舰。參數(shù)標(biāo)簽在調(diào)用函數(shù)時(shí)使用晶府;每個(gè)參數(shù)都寫在函數(shù)調(diào)用中,其參數(shù)標(biāo)簽在參數(shù)之前钻趋。參數(shù)名用于函數(shù)的實(shí)現(xiàn)川陆。默認(rèn)情況下,參數(shù)使用其參數(shù)名稱作為參數(shù)標(biāo)簽蛮位。
func someFunction(firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
someFunction(firstParameterName: 1, secondParameterName: 2)
所有參數(shù)必須具有唯一的名稱较沪。盡管多個(gè)參數(shù)可能具有相同的參數(shù)標(biāo)簽,但唯一的參數(shù)標(biāo)簽有助于提高代碼的可讀性失仁。
指定參數(shù)標(biāo)簽
在參數(shù)名稱前寫一個(gè)參數(shù)標(biāo)簽尸曼,用空格分隔:
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
下面是greet(person:)
函數(shù)的一個(gè)變體,它接收一個(gè)人的姓名和家鄉(xiāng)并返回問候語:
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// Prints "Hello Bill! Glad you could visit from Cupertino."
參數(shù)標(biāo)簽的使用可以讓函數(shù)以一種表達(dá)性的萄焦、類似句子的方式被調(diào)用控轿,同時(shí)仍然提供一個(gè)可讀的、意圖清晰的函數(shù)體。
省略參數(shù)標(biāo)簽
如果不需要參數(shù)的參數(shù)標(biāo)簽解幽,請(qǐng)為該參數(shù)編寫下劃線(_)
來代替顯式的參數(shù)標(biāo)簽贴见。
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
someFunction(1, secondParameterName: 2)
如果參數(shù)有參數(shù)標(biāo)簽,則在調(diào)用函數(shù)時(shí)必須使用標(biāo)簽標(biāo)記參數(shù)躲株。
默認(rèn)參數(shù)值
通過在參數(shù)類型之后為參數(shù)賦值片部,可以為函數(shù)中的任何參數(shù)定義默認(rèn)值。如果定義了默認(rèn)值霜定,則可以在調(diào)用函數(shù)時(shí)忽略該參數(shù)档悠。
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// If you omit the second argument when calling this function, then
// the value of parameterWithDefault is 12 inside the function body.
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault is 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault is 12
將沒有默認(rèn)值的參數(shù)放在函數(shù)參數(shù)列表的開頭,也就是放在具有默認(rèn)值的參數(shù)之前望浩。對(duì)于函數(shù)的意義來說辖所,沒有默認(rèn)值的參數(shù)通常更為重要,先編寫它們可以更容易地識(shí)別調(diào)用的是同一個(gè)函數(shù)磨德,而不用管是否省略了其他有默認(rèn)只的參數(shù)缘回。
可變參數(shù)
可變參數(shù)接受指定類型的零個(gè)或多個(gè)值。我們可以使用可變參數(shù)來指定在調(diào)用函數(shù)時(shí)可以向參數(shù)傳遞不同數(shù)量的輸入值典挑。通過在參數(shù)的類型名稱后插入三個(gè)句點(diǎn)字符(…)來寫入可變參數(shù)酥宴。
在函數(shù)體中,傳遞給可變參數(shù)的值作為適當(dāng)類型的數(shù)組來用您觉。例如拙寡,一個(gè)名為numbers、類型為Double...的可變參數(shù)琳水,在函數(shù)體中作為[Double]類型的numbers常量數(shù)組來使用肆糕。
下面的示例計(jì)算任意長(zhǎng)度的數(shù)字列表的算術(shù)平均值(也稱為平均值):
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)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers
可變參數(shù)后面的第一個(gè)參數(shù)必須有參數(shù)標(biāo)簽。參數(shù)標(biāo)簽可以明確哪些參數(shù)是傳遞給可變參數(shù)在孝,哪些參數(shù)是傳遞給可變參數(shù)后面的參數(shù)诚啃。
一個(gè)函數(shù)可以有多個(gè)可變參數(shù)。
in-out參數(shù)
默認(rèn)情況下浑玛,函數(shù)參數(shù)是常量绍申。嘗試從函數(shù)體中更改函數(shù)參數(shù)的值會(huì)導(dǎo)致編譯時(shí)錯(cuò)誤。這意味著我們不能錯(cuò)誤地更改參數(shù)的值顾彰。如果希望讓函數(shù)可以修改參數(shù)的值,并且希望這些更改在函數(shù)調(diào)用結(jié)束后保持不變胃碾,請(qǐng)將該參數(shù)定義為in-out參數(shù)涨享。
我們可以通過將inout關(guān)鍵字放在參數(shù)的類型之前來編寫in-out參數(shù)。in-out參數(shù)有一個(gè)值仆百,該值傳入函數(shù)厕隧,可以由函數(shù)修改,然后從函數(shù)中傳回以替換原始值。有關(guān)輸入輸出參數(shù)的行為和相關(guān)編譯器優(yōu)化的詳細(xì)討論吁讨,請(qǐng)參閱輸入輸出參數(shù)髓迎。
只能將變量作為輸入輸出參數(shù)的參數(shù)傳遞。不能傳遞常量或文字值作為參數(shù)建丧,因?yàn)槌A亢臀淖植荒苄薷呐帕洹.?dāng)我們將變量作為參數(shù)傳遞給in-out參數(shù)時(shí),可以在變量名稱前直接放置一個(gè)符號(hào)(&)翎朱,以指示函數(shù)可以修改它橄维。
注意
in-out參數(shù)不能有默認(rèn)值,并且可變參數(shù)不能標(biāo)記為in-out參數(shù)拴曲。
下面是一個(gè)名為swapTwoInts(_:_:)
的函數(shù)示例争舞,它有兩個(gè)名為a和b的輸入輸出整數(shù)參數(shù):
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoInts(_:_:)
函數(shù)只是將b的值交換給a,將a的值交換給b澈灼。該函數(shù)通過將a的值存儲(chǔ)在臨時(shí)常量temporaryA中竞川,將b的值賦給a,然后將temporaryA賦給b來執(zhí)行交換叁熔。
我們可以使用Int類型的兩個(gè)變量調(diào)用swapTwoInts(_:_:)
函數(shù)來交換它們的值委乌。請(qǐng)注意,someInt
和anotherInt
的名稱在傳遞給swapTwoInts(_:_:)
函數(shù)時(shí)者疤,前面會(huì)加上一個(gè)&的符號(hào):
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"
上面的示例顯示someInt
和anotherInt
的原始值是由swapTwoInts(_:_:)
函數(shù)修改的福澡,即使它們最初是在函數(shù)外部定義的。
注意
In-out參數(shù)和函數(shù)的返回值是不同的驹马。上面的swapTwoInts示例沒有定義返回類型或返回值革砸,但它仍然修改someInt
和anotherInt
的值。In-out參數(shù)是函數(shù)在其函數(shù)體范圍之外產(chǎn)生效果的另一種方法糯累。
函數(shù)類型
每個(gè)函數(shù)都有一個(gè)特定的函數(shù)類型算利,由函數(shù)的參數(shù)類型和返回值類型組成。
例如:
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
這個(gè)例子定義了兩個(gè)簡(jiǎn)單的數(shù)學(xué)函數(shù)addTwoInts
和multiplyTwoInts
泳姐。這些函數(shù)分別輸入兩個(gè)Int值效拭,并返回一個(gè)Int值,這個(gè)返回值是執(zhí)行適當(dāng)?shù)臄?shù)學(xué)運(yùn)算的結(jié)果胖秒。
這兩個(gè)函數(shù)的類型都是(Int, Int) -> Int
缎患。這可以理解為:
一種函數(shù),它有兩個(gè)參數(shù)阎肝,都是Int類型的挤渔,并且返回Int類型的值
下面是另一個(gè)示例,是一個(gè)沒有參數(shù)或返回值的函數(shù):
func printHelloWorld() {
print("hello, world")
}
此函數(shù)的類型是() -> Void
风题,或者可以說是“沒有參數(shù)并且返回Void的函數(shù)”
使用函數(shù)類型
我們使用函數(shù)類型就像Swift中的其他類型一樣判导。例如嫉父,可以將常量或變量定義為函數(shù)類型,并為該變量指定適當(dāng)?shù)暮瘮?shù):
var mathFunction: (Int, Int) -> Int = addTwoInts
這可以理解為:
定義一個(gè)名為mathFunction
的變量眼刃,該變量的類型為“接受兩個(gè)Int值并返回一個(gè)Int值的函數(shù)”绕辖。將此新變量設(shè)置為引用名為addTwoInts
的函數(shù)
addTwoInts(_:_:)
函數(shù)與mathFunction
變量具有相同的類型,因此Swift的類型檢查器允許此賦值擂红。
現(xiàn)在可以使用mathFunction調(diào)用指定的函數(shù):
print("Result: \(mathFunction(2, 3))")
// Prints "Result: 5"
具有相同匹配類型的不同函數(shù)可以分配給同一變量仪际,方法與非函數(shù)類型相同:
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// Prints "Result: 6"
與任何其他類型一樣,當(dāng)我們將函數(shù)賦給常量或變量時(shí)篮条,我們可以讓Swift來推斷函數(shù)類型:
let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int
函數(shù)類型作為參數(shù)類型
可以使用(Int, Int) -> Int
等函數(shù)類型作為另一個(gè)函數(shù)的參數(shù)類型弟头。這使我們能夠在調(diào)用函數(shù)時(shí)將函數(shù)實(shí)現(xiàn)的某些方面留給函數(shù)的調(diào)用方提供。
下面是一個(gè)打印上面d的函數(shù)結(jié)果的示例:
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Prints "Result: 8"
本例定義了一個(gè)名為printMathResult(_:_:_:)
的函數(shù)涉茧,該函數(shù)有三個(gè)參數(shù)赴恨。第一個(gè)參數(shù)稱為mathFunction
,其類型為(Int伴栓,Int)->Int
伦连。我們可以傳遞該類型的任何函數(shù)作為第一個(gè)參數(shù)的值。第二個(gè)和第三個(gè)參數(shù)稱為a和b钳垮,它們都是Int類型的惑淳。它們被用作提供的mathFunction函數(shù)的兩個(gè)輸入值。
當(dāng)調(diào)用printMathResult(_:_:_:)
時(shí)饺窿,將addTwoInts(_:_:)
函數(shù)以及整數(shù)值3和5傳遞給它歧焦。它用值3和5調(diào)用提供的函數(shù),并打印8的結(jié)果肚医。
printMathResult(_:_:_:)
的作用是打印調(diào)用適當(dāng)類型的mathFunction函數(shù)的結(jié)果绢馍。不管函數(shù)的實(shí)現(xiàn)是什么,重要的是函數(shù)的類型是否正確肠套。這使得printMathResult(_:_:_:)
能夠以類型安全的方式將其某些功能傳遞給函數(shù)的調(diào)用者舰涌。
函數(shù)類型作為返回類型
可以使用函數(shù)類型作為另一個(gè)函數(shù)的返回類型。我們可以通過在返回函數(shù)的返回箭頭(->)
之后立即編寫完整的函數(shù)類型來完成此操作你稚。
下一個(gè)示例定義了兩個(gè)簡(jiǎn)單的函數(shù)瓷耙,稱為stepForward(_:)
和stepBackward(_:)
。stepForward(_:)
函數(shù)返回的值比其輸入值大一個(gè)刁赖,stepBackward(_:)
函數(shù)返回的值比其輸入值小一個(gè)搁痛。兩個(gè)函數(shù)的類型都是(Int) -> Int
:
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
下面是一個(gè)名為chooseStepFunction(backward:)
的函數(shù),其返回類型為(Int)-> Int
宇弛。chooseStepFunction(backward:)
函數(shù)基于一個(gè)名為backward
的布爾參數(shù)返回stepForward(_:)
或stepBackward(_:)
函數(shù):
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
現(xiàn)在可以使用chooseStepFunction(backward:)
獲取一個(gè)將向一個(gè)方向或另一個(gè)方向移動(dòng)的函數(shù):
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function
上面的例子決定了將一個(gè)名為currentValue的變量逐漸移近零是需要一個(gè)正的步向還是負(fù)的步向落追。currentValue
的初始值為3,這意味著currentValue > 0
返回true涯肩,從而導(dǎo)致chooseStepFunction(backward:)
返回stepBackward(_:)
函數(shù)轿钠。返回函數(shù)的引用存儲(chǔ)在名為moveNearerToZero
的常量中。
現(xiàn)在moveNearerToZero
引用了正確的函數(shù)病苗,可以使用它來計(jì)數(shù)為零:
print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!
嵌套的函數(shù)
到目前為止疗垛,我們?cè)诒菊轮杏龅降乃泻瘮?shù)都是在全局范圍內(nèi)定義的全局函數(shù)的示例。我們還可以在其他函數(shù)體中定義函數(shù)硫朦,稱為嵌套函數(shù)贷腕。
默認(rèn)情況下,嵌套函數(shù)對(duì)外隱藏咬展,但仍可以由其外層封閉函數(shù)調(diào)用和使用泽裳。外層封閉函數(shù)還可以返回一個(gè)其中的嵌套函數(shù),以允許在另一個(gè)作用域中使用該嵌套函數(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!