Swift 函數(shù)

函數(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)注意,someIntanotherInt的名稱在傳遞給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"

上面的示例顯示someIntanotherInt的原始值是由swapTwoInts(_:_:)函數(shù)修改的福澡,即使它們最初是在函數(shù)外部定義的。

注意
In-out參數(shù)和函數(shù)的返回值是不同的驹马。上面的swapTwoInts示例沒有定義返回類型或返回值革砸,但它仍然修改someIntanotherInt的值。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ù)addTwoIntsmultiplyTwoInts泳姐。這些函數(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!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涮总,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子祷舀,更是在濱河造成了極大的恐慌瀑梗,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裳扯,死亡現(xiàn)場(chǎng)離奇詭異抛丽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)饰豺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門亿鲜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人冤吨,你說我怎么就攤上這事蒿柳。” “怎么了锅很?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵其馏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我爆安,道長(zhǎng)叛复,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任扔仓,我火速辦了婚禮褐奥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翘簇。我一直安慰自己撬码,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布版保。 她就那樣靜靜地躺著呜笑,像睡著了一般夫否。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叫胁,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天凰慈,我揣著相機(jī)與錄音,去河邊找鬼驼鹅。 笑死微谓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的输钩。 我是一名探鬼主播豺型,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼买乃!你這毒婦竟也來了姻氨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤为牍,失蹤者是張志新(化名)和其女友劉穎哼绑,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碉咆,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抖韩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疫铜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茂浮。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖壳咕,靈堂內(nèi)的尸體忽然破棺而出席揽,到底是詐尸還是另有隱情,我是刑警寧澤谓厘,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布幌羞,位于F島的核電站,受9級(jí)特大地震影響竟稳,放射性物質(zhì)發(fā)生泄漏属桦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一他爸、第九天 我趴在偏房一處隱蔽的房頂上張望聂宾。 院中可真熱鬧,春花似錦诊笤、人聲如沸系谐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纪他。三九已至鄙煤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間止喷,已是汗流浹背馆类。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弹谁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓句喜,卻偏偏與公主長(zhǎng)得像预愤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咳胃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)是一段完成特定任務(wù)的獨(dú)立代碼片段植康。你可以通過給函數(shù)命名來標(biāo)識(shí)某個(gè)函數(shù)的功能,這個(gè)名字可以被用來在需要的時(shí)候"調(diào)...
    CDLOG閱讀 208評(píng)論 0 0
  • 函數(shù)定義與調(diào)用 無參數(shù)来惧,無返回值(沒有定義返回類型的函數(shù)會(huì)返回Void冗栗,它其實(shí)是一個(gè)空的元組,可以寫成()) 有參...
    皆為序幕_閱讀 513評(píng)論 0 1
  • 函數(shù)是用來完成特定任務(wù)的獨(dú)立的代碼塊。給一個(gè)函數(shù)起一個(gè)合適的名字供搀,用來標(biāo)識(shí)函數(shù)做什么隅居,并且當(dāng)函數(shù)需要執(zhí)行的時(shí)候,這...
    窮人家的孩紙閱讀 810評(píng)論 2 1
  • 函數(shù) 函數(shù)是一段完成特定任務(wù)的獨(dú)立代碼片段葛虐。你可以通過給函數(shù)命名來標(biāo)識(shí)某個(gè)函數(shù)的功能胎源,這個(gè)名字可以被用來在需要的時(shí)...
    趙哥窟閱讀 362評(píng)論 0 0
  • 函數(shù) 函數(shù)是一段完成特定任務(wù)的獨(dú)立代碼片段。你可以通過給函數(shù)命名來標(biāo)識(shí)某個(gè)函數(shù)的功能屿脐,這個(gè)名字可以被用來在需要的時(shí)...
    Longshihua閱讀 359評(píng)論 0 0