引言
繼續(xù)學(xué)習(xí)Swift文檔,從上一章節(jié):控制流但指,我們學(xué)習(xí)了Swift控制流相關(guān)的內(nèi)容寡痰,如for-in循環(huán)、while循環(huán)棋凳、if語句拦坠、switch語句、continue剩岳、break贞滨、fallthrough、帶標(biāo)簽的語句拍棕、guard語句這些內(nèi)容晓铆。其中switch語句在swift里的用法與OC相比,有很大的差別绰播,功能更豐富骄噪,具體的可以參閱上一章節(jié)的內(nèi)容。現(xiàn)在幅垮,我們學(xué)習(xí)Swift的函數(shù)相關(guān)的內(nèi)容腰池。這一章節(jié)的內(nèi)容很重要了尾组,幾乎所有開發(fā)語言都離不開函數(shù)的使用忙芒,所以我們要認(rèn)真對待并熟練掌握這一章節(jié)的內(nèi)容示弓。由于篇幅較長,這里分篇來記錄呵萨,接下來奏属,F(xiàn)ighting!
如果你已經(jīng)熟練掌握了函數(shù)的使用潮峦,那么請參閱下一章節(jié):閉包
函數(shù)
函數(shù)是執(zhí)行特定任務(wù)的獨(dú)立代碼塊囱皿。 您為函數(shù)指定一個名稱,該名稱可以標(biāo)識其功能忱嘹,并且該名稱用于“調(diào)用”該函數(shù)以在需要時執(zhí)行其任務(wù)嘱腥。
Swift的統(tǒng)一函數(shù)語法足夠靈活,可以表達(dá)任何內(nèi)容拘悦,從沒有參數(shù)名稱的簡單C樣式函數(shù)到具有每個參數(shù)名稱和參數(shù)標(biāo)簽的復(fù)雜的Objective-C樣式方法齿兔。 參數(shù)可以提供默認(rèn)值以簡化函數(shù)調(diào)用,并且可以作為輸入-輸出參數(shù)傳遞础米,參數(shù)在函數(shù)完成執(zhí)行后會修改傳遞的變量分苇。
Swift中的每個函數(shù)都有一個類型,包括該函數(shù)的參數(shù)類型和返回類型屁桑。 您可以像Swift中的任何其他類型一樣使用此類型医寿,這使得將函數(shù)作為參數(shù)傳遞給其他函數(shù)以及從函數(shù)返回函數(shù)變得容易。 也可以在其他函數(shù)中編寫函數(shù)蘑斧,以將有用的函數(shù)封裝在嵌套函數(shù)范圍內(nèi)靖秩。
1 定義和調(diào)用函數(shù)
定義函數(shù)時,可以選擇定義一個或多個該函數(shù)作為輸入的命名竖瘾,鍵入的值沟突,稱為參數(shù)。 您還可以選擇定義一種值類型准浴,該函數(shù)完成后將作為輸出傳回事扭,稱為函數(shù)的返回類型。
每個功能都有一個功能名稱乐横,該名稱描述了該功能執(zhí)行的任務(wù)求橄。 要使用函數(shù),請使用函數(shù)名稱“調(diào)用”該函數(shù)葡公,然后將與函數(shù)參數(shù)類型匹配的輸入值(稱為自變量)傳遞給它罐农。 必須始終以與函數(shù)參數(shù)列表相同的順序提供函數(shù)的參數(shù)。
在下面的示例中催什,該函數(shù)稱為greet(person :)涵亏,因為它就是這樣做的,它將一個人的名字作為輸入并返回該人的問候語。 為此气筋,您需要定義一個輸入?yún)?shù)-一個名為person的String值拆内,以及一個String返回類型,其中將包含對該人的問候:
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}
所有這些信息都會匯總到函數(shù)的定義中宠默,并以func關(guān)鍵字為前綴麸恍。 您可以使用返回箭頭->(連字符后接直角括號)指示函數(shù)的返回類型,其后是要返回的類型的名稱搀矫。
定義描述了函數(shù)的功能抹沪,期望接收的功能以及完成后返回的內(nèi)容。 通過定義瓤球,可以輕松地從代碼中的其他地方明確調(diào)用該函數(shù):
print(greet(person: "Anna"))
// Prints "Hello, Anna!"
print(greet(person: "Brian"))
// Prints "Hello, Brian!"
您可以通過在person參數(shù)標(biāo)簽之后傳遞一個String值來調(diào)用greet(person :)函數(shù)融欧,例如greet(person:“ Anna”)。 由于該函數(shù)返回一個String值卦羡,因此可以將greet(person :)包裝在對print(_:separator:terminator :)函數(shù)的調(diào)用中噪馏,以打印該字符串并查看其返回值,如上所示虹茶。
注意
print(_:separator:terminator :)函數(shù)的第一個參數(shù)沒有標(biāo)簽逝薪,其他參數(shù)是可選的,因為它們具有默認(rèn)值蝴罪。 有關(guān)函數(shù)語法的這些變體董济,將在下面的“函數(shù)參數(shù)標(biāo)簽”,“參數(shù)名稱”和“默認(rèn)參數(shù)值”中進(jìn)行討論要门。
greet(person :)函數(shù)的主體通過定義一個新的String常量(稱為greeting)并將其設(shè)置為簡單的問候消息開始虏肾。 然后,使用return關(guān)鍵字將此greeting傳回函數(shù)欢搜。 在表示返回greeting的代碼行中封豪,該函數(shù)完成其執(zhí)行并返回greeting的當(dāng)前值。
您可以使用不同的輸入值多次調(diào)用greet(person :)函數(shù)炒瘟。 上面的示例顯示了如果使用輸入值“ Anna”和輸入值“ Brian”進(jìn)行調(diào)用會發(fā)生的情況吹埠。 該函數(shù)在每種情況下都會返回定制的問候語。
為了使該函數(shù)的主體更短疮装,可以將消息創(chuàng)建和return語句合并為一行:
func greetAgain(person: String) -> String {
return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// Prints "Hello again, Anna!"
2 函數(shù)參數(shù)和返回值
函數(shù)參數(shù)和返回值在Swift中非常靈活缘琅。 您可以定義任何東西,從具有單個未命名參數(shù)的簡單實用程序函數(shù)到具有表達(dá)性參數(shù)名稱和不同參數(shù)選項的復(fù)雜函數(shù)廓推。
2.1 沒有參數(shù)的函數(shù)
不需要功能來定義輸入?yún)?shù)刷袍。 這是一個沒有輸入?yún)?shù)的函數(shù),無論何時調(diào)用樊展,該函數(shù)總是返回相同的String消息:
func sayHelloWorld() -> String {
return "hello, world"
}
print(sayHelloWorld())
// Prints "hello, world"
盡管函數(shù)定義沒有任何參數(shù)呻纹,但仍需要在函數(shù)名稱后加上括號堆生。 調(diào)用函數(shù)時,函數(shù)名稱后還會有一對空括號雷酪。
2.2 多個參數(shù)的函數(shù)
函數(shù)可以具有多個輸入?yún)?shù)淑仆,這些參數(shù)寫在函數(shù)的括號內(nèi),并用逗號分隔太闺。
此函數(shù)接受一個人的名字以及是否已經(jīng)打過招呼糯景,然后返回該人的問候語:
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!"
您可以通過在圓括號中將標(biāo)為person的String參數(shù)值和標(biāo)為hasgreeted的Bool參數(shù)值都傳遞給括號來調(diào)用greet(person:alreadyGreeted :)函數(shù)嘁圈,并用逗號分隔省骂。 請注意,此函數(shù)不同于前面部分中顯示的greet(person :)函數(shù)最住。 盡管兩個函數(shù)的名稱都以greet開頭钞澳,但是greet(person:alreadyGreeted :)函數(shù)采用兩個參數(shù),而greet(person :)函數(shù)僅采用一個參數(shù)涨缚。
2.3 沒有返回值的函數(shù)
不需要函數(shù)來定義返回類型轧粟。 這是greet(person :)函數(shù)的一個版本,該函數(shù)打印其自己的String值脓魏,而不是返回該值:
func greet(person: String) {
print("Hello, \(person)!")
}
greet(person: "Dave")
// Prints "Hello, Dave!"
因為它不需要返回值兰吟,所以函數(shù)的定義不包含返回箭頭(->)或返回類型。
注意
嚴(yán)格來說茂翔,即使未定義返回值混蔼,此版本的greet(person :)函數(shù)仍會返回值。 沒有定義返回類型的函數(shù)將返回Void類型的特殊值珊燎。 這只是一個空元組惭嚣,寫為()。
調(diào)用函數(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 does not return a value
第一個函數(shù)printAndCount(string :)打印一個字符串晚吞,然后將其字符計數(shù)作為Int返回。 第二個函數(shù)printWithoutCounting(string :)調(diào)用第一個函數(shù)谋国,但忽略其返回值槽地。 當(dāng)調(diào)用第二個函數(shù)時,消息仍然由第一個函數(shù)打印芦瘾,但是不使用返回的值捌蚊。
注意
返回值可以忽略,但是說返回值的函數(shù)必須始終這樣做旅急。 在函數(shù)的底部結(jié)束時逢勾,具有定義了返回類型的函數(shù)不返回值,會導(dǎo)致編譯時錯誤藐吮。
2.4 多個返回值的函數(shù)
您可以使用元組類型作為函數(shù)的返回類型溺拱,以將多個值作為一個復(fù)合返回值的一部分返回逃贝。
下面的示例定義了一個名為minMax(array :)的函數(shù),該函數(shù)查找Int值數(shù)組中的最小和最大數(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ù)返回一個包含兩個Int值的元組迫摔。 這些值分別標(biāo)記為min和max沐扳,以便在查詢函數(shù)的返回值時可以按名稱訪問它們。
minMax(array :)函數(shù)的主體通過將兩個名為currentMin和currentMax的工作變量設(shè)置為數(shù)組中第一個整數(shù)的值開始句占。 然后沪摄,該函數(shù)循環(huán)訪問數(shù)組中的其余值,并檢查每個值是否分別小于或大于currentMin和currentMax的值纱烘。 最后杨拐,總的最小值和最大值作為兩個Int值的元組返回。
由于元組的成員值是函數(shù)返回類型的一部分擂啥,因此可以使用點語法訪問它們哄陶,以檢索找到的最小值和最大值:
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ù)返回元組時不需要命名元組的成員哺壶,因為它們的名稱已被指定為函數(shù)返回類型的一部分屋吨。
2.5 可選的元組返回類型
如果要函數(shù)返回的元組類型,可能是“無值”,則可以使用可選的元組返回類型來反映整個元組可以為零山宾。 您通過在元組類型的右括號后面加上問號來編寫可選的元組返回類型至扰,例如(Int,Int)资锰? 或(字符串敢课,整數(shù),布爾)台妆?
注意
可選的元組類型翎猛,例如(Int,Int)接剩? 與包含可選類型(例如(Int ?, Int切厘?))的元組不同。 對于可選的元組類型懊缺,整個元組是可選的疫稿,而不僅僅是元組中的每個單獨(dú)的值。
上面的minMax(array :)函數(shù)返回一個包含兩個Int值的元組鹃两。 但是遗座,該函數(shù)不會對傳遞的數(shù)組執(zhí)行任何安全檢查。 如果array參數(shù)包含一個空數(shù)組俊扳,則如上所述途蒋,minMax(array :)函數(shù)將在嘗試訪問array [0]時觸發(fā)運(yùn)行時錯誤。
為了安全地處理空數(shù)組馋记,請編寫具有可選元組返回類型的minMax(array :)函數(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ù)是否返回實際的元組值或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"
2.6 隱式返回函數(shù)
如果函數(shù)的整個主體是單個表達(dá)式懊烤,則函數(shù)隱式返回該表達(dá)式。 例如宽堆,下面的兩個函數(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ù)定義的是它返回的問候消息腌紧,這意味著它可以使用這種較短的形式。 anotherGreeting(for :)函數(shù)使用類似的函數(shù)的return關(guān)鍵字返回相同的問候消息畜隶。 您只寫一個返回行的任何函數(shù)都可以忽略該返回壁肋。
就像在Shorthand Getter Declaration中所看到的那樣,屬性getter也可以使用隱式返回籽慢。
3 函數(shù)參數(shù)標(biāo)簽和參數(shù)名稱
每個函數(shù)參數(shù)都具有參數(shù)標(biāo)簽和參數(shù)名稱浸遗。 參數(shù)標(biāo)簽在調(diào)用函數(shù)時使用; 每個參數(shù)都寫在函數(shù)調(diào)用中嗡综,并帶有其參數(shù)標(biāo)簽乙帮。 參數(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ù)必須具有唯一的名稱驾茴。 盡管多個參數(shù)可能具有相同的參數(shù)標(biāo)簽盼樟,但獨(dú)特的參數(shù)標(biāo)簽有助于使代碼更具可讀性。
3.1 指定參數(shù)標(biāo)簽
您在參數(shù)名稱前寫一個參數(shù)標(biāo)簽锈至,并用空格隔開:
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
這是greet(person :)函數(shù)的一種變體晨缴,它帶有一個人的名字和家鄉(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."
變量標(biāo)簽的使用可以讓函數(shù)以表達(dá)方式,類似于句子的方式被調(diào)用峡捡,同時還可以提供可讀且意圖明確的函數(shù)主體击碗。
3.2 省略參數(shù)標(biāo)簽
如果您不希望為參數(shù)添加參數(shù)標(biāo)簽,請為該參數(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ù)進(jìn)行標(biāo)簽。
3.3 默認(rèn)參數(shù)值
您可以為函數(shù)中的任何參數(shù)定義默認(rèn)值砚婆,方法是在該參數(shù)的類型之后為該參數(shù)分配一個值械拍。 如果定義了默認(rèn)值,則可以在調(diào)用函數(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ù)之前。 沒有默認(rèn)值的參數(shù)通常對函數(shù)的意義更重要-首先編寫它們可以使您更容易識別正在調(diào)用相同的函數(shù)埂奈,而不管是否忽略了任何默認(rèn)參數(shù)迄损。
3.4 可變參數(shù)
可變參數(shù)接受零個或多個指定類型的值。 您可以使用可變參數(shù)來指定在調(diào)用函數(shù)時可以向該參數(shù)傳遞不同數(shù)量的輸入值账磺。 通過在參數(shù)的類型名稱后插入三個句點(...)來編寫可變參數(shù)芹敌。
傳遞給可變參數(shù)的值可在函數(shù)體內(nèi)以適當(dāng)類型的數(shù)組形式使用共屈。 例如,在函數(shù)體內(nèi)可以使用帶有數(shù)字名稱和Double ...類型的可變參數(shù)作為稱為Numbers [Double]類型的常量數(shù)組党窜。
下面的示例為任意長度的數(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ù)最多可以具有一個可變參數(shù)拗引。
3.5 in-out參數(shù)
函數(shù)參數(shù)默認(rèn)為常量。 試圖從函數(shù)主體內(nèi)部更改函數(shù)參數(shù)的值會導(dǎo)致編譯時錯誤幌衣。 這意味著您不能錯誤地更改參數(shù)的值矾削。 如果您希望函數(shù)修改參數(shù)的值,并且希望這些更改在函數(shù)調(diào)用結(jié)束后仍然存在豁护,請將該參數(shù)定義為in-out參數(shù)哼凯。
您可以通過將in-out關(guān)鍵字放在參數(shù)類型的前面來編寫in-out參數(shù)。 in-out參數(shù)具有一個值楚里,該值傳遞給函數(shù)断部,由函數(shù)修改,然后傳遞回函數(shù)以替換原始值班缎。 有關(guān)in-out參數(shù)的行為以及相關(guān)的編譯器優(yōu)化的詳細(xì)討論蝴光,請參見In-Out Parameters。
您只能將變量作為in-out參數(shù)的參數(shù)傳遞达址。 您不能將常量或文字值作為參數(shù)傳遞蔑祟,因為無法修改常量和文字。 當(dāng)您將"與"符號(&)用作變量的參數(shù)時沉唠,可以直接在其名稱前放置一個&符號疆虚,以表明該變量可以被函數(shù)修改。
注意
in-out 參數(shù)不能有默認(rèn)值满葛,并且可變參數(shù)不能被用為in-out參數(shù)
這是一個名為swapTwoInts(: :)的函數(shù)的示例径簿,該函數(shù)具有兩個稱為a和b的in-out整數(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的值存儲在一個稱為臨時A的臨時常量中篇亭,然后將b的值賦給a,然后將臨時A賦給b來執(zhí)行此交換乳蛾。
您可以使用兩個Int類型的變量調(diào)用swapTwoInts(: :)函數(shù)來交換它們的值暗赶。 請注意,當(dāng)將someInt和anotherInt的名稱傳遞給swapTwoInts(: :)函數(shù)時肃叶,它們的前綴為&符:
ar 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的值。 in0out參數(shù)是函數(shù)在函數(shù)主體范圍之外產(chǎn)生影響的另一種方法蹦魔。
4 函數(shù)類型
每個函數(shù)都有特定的函數(shù)類型激率,由函數(shù)的參數(shù)類型和返回類型組成咳燕。
例如:
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
此示例定義了兩個簡單的數(shù)學(xué)函數(shù),分別稱為addTwoInts和multipleTwoInts乒躺。 這些函數(shù)各自采用兩個Int值招盲,并返回一個Int值,這是執(zhí)行適當(dāng)?shù)臄?shù)學(xué)運(yùn)算的結(jié)果嘉冒。
這兩個函數(shù)的類型都是(Int曹货,Int)-> Int。 可以理解為:
“具有兩個參數(shù)(均為Int類型)并且返回值為Int類型的值的函數(shù)讳推《プ眩”
這是另一個示例,針對沒有參數(shù)或返回值的函數(shù):
func printHelloWorld() {
print("hello, world")
}
此函數(shù)的類型為()-> Void银觅,或“沒有參數(shù)并返回Void的函數(shù)”礼饱。
4.1 使用函數(shù)類型
您可以像使用Swift中的其他類型一樣使用函數(shù)類型。 例如究驴,您可以將常量或變量定義為函數(shù)類型镊绪,然后為該變量分配適當(dāng)?shù)暮瘮?shù):
var mathFunction: (Int, Int) -> Int = addTwoInts
“定義一個名為mathFunction的變量,該變量的類型為'一個具有兩個Int值的函數(shù)纳胧,并返回一個Int值镰吆。'將此新變量設(shè)置為引用名為addTwoInts的函數(shù)∨苣剑”
addTwoInts(: :)函數(shù)的類型與mathFunction變量的類型相同,因此Swift的類型檢查器允許進(jìn)行此分配摧找。
現(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"
與任何其他類型一樣蹬耘,在將函數(shù)分配給常量或變量時芝雪,可以將其留給Swift來推斷函數(shù)類型:
let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int
4.2 函數(shù)類型作為參數(shù)
您可以使用諸如(Int,Int)-> Int之類的函數(shù)類型作為另一個函數(shù)的參數(shù)類型综苔。 這樣一來惩系,您就可以將函數(shù)實現(xiàn)的某些方面留給函數(shù)的調(diào)用方在調(diào)用函數(shù)時提供。
這是一個從上方打印數(shù)學(xué)函數(shù)結(jié)果的示例:
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Prints "Result: 8"
本示例定義了一個名為printMathResult(::_ :)的函數(shù)如筛,該函數(shù)具有三個參數(shù)堡牡。 第一個參數(shù)稱為mathFunction,類型為(Int杨刨,Int)-> Int晤柄。 您可以將該類型的任何函數(shù)作為第一個參數(shù)的參數(shù)傳遞。 第二個和第三個參數(shù)分別稱為a和b妖胀,并且均為Int類型芥颈。 這些用作提供的數(shù)學(xué)函數(shù)的兩個輸入值惠勒。
調(diào)用printMathResult(::_ :)時,將傳遞addTwoInts(: :)函數(shù)以及整數(shù)值3和5爬坑。它將調(diào)用提供的函數(shù)纠屋,其值分別為3和5,并打印結(jié)果 8盾计。
printMathResult(::_ :)的作用是打印對適當(dāng)類型的數(shù)學(xué)函數(shù)的調(diào)用結(jié)果售担。 該函數(shù)的實現(xiàn)實際執(zhí)行什么無關(guān)緊要,僅與該函數(shù)的類型正確無關(guān)闯估。 這使printMathResult(::_ :)以類型安全的方式將其某些功能移交給函數(shù)的調(diào)用者灼舍。
4.3 函數(shù)類型作為返回值
您可以將一個函數(shù)類型用作另一個函數(shù)的返回類型。 您可以通過在返回函數(shù)的返回箭頭(->)之后立即編寫完整的函數(shù)類型來執(zhí)行此操作涨薪。
下一個示例定義了兩個簡單的函數(shù)骑素,分別稱為stepForward(_ :)和stepBackward(_ :)。 stepForward(_ :)函數(shù)返回的值比其輸入值大一刚夺,而stepBackward(_ :)函數(shù)返回的值比其輸入值小一献丑。 這兩個函數(shù)的類型都是(Int)-> Int:
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
這是一個名為choiceStepFunction(backward :)的函數(shù),其返回類型為(Int)-> Int侠姑。 choiceStepFunction(backward :)函數(shù)基于布爾值向后返回stepForward(_ :)函數(shù)或stepBackward(_ :)函數(shù):
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
現(xiàn)在创橄,您可以使用choiceStepFunction(backward :)來獲得向一個方向或另一個方向步進(jìn)的函數(shù):
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function
上面的示例確定是否需要正步或負(fù)步來逐步將名為currentValue的變量逐漸移近零。 currentValue的初始值為3莽红,這意味著currentValue> 0返回true妥畏,從而導(dǎo)致selectStepFunction(backward :)返回stepBackward(_ :)函數(shù)。 對返回函數(shù)的引用存儲在名為moveNearerToZero的常量中安吁。
現(xiàn)在moveNearerToZero引用了正確的函數(shù)醉蚁,它可以用于計數(shù)為零:
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ù)是在全局范圍內(nèi)定義的网棍。 您還可以在其他函數(shù)體內(nèi)定義函數(shù),稱為嵌套函數(shù)妇智。
嵌套函數(shù)默認(rèn)情況下對外界隱藏滥玷,但仍可以由其封閉函數(shù)調(diào)用和使用。 封閉函數(shù)還可以返回其嵌套函數(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!
總結(jié)
這一章節(jié)內(nèi)容到這里就結(jié)束了,我們做個小結(jié):
- 函數(shù)的定義和調(diào)用拉盾。
- 函數(shù)可以攜帶參數(shù)或者不帶參數(shù)桨菜。
- 函數(shù)可以有返回值,作為該函數(shù)的類型,返回值寫在->符號的后面倒得;可以有多個返回值泻红,如:返回值為元組;可選的元組返回類型在元組后面加?符號霞掺。
- 函數(shù)可以沒有返回值谊路,則該函數(shù)的類型為void類型,默認(rèn)可以省略->符號和void類型菩彬。
- 函數(shù)參數(shù)標(biāo)簽缠劝,也就是函數(shù)參數(shù)名,在調(diào)用函數(shù)時骗灶,可以省略函數(shù)參數(shù)惨恭,做法是在聲明函數(shù)時,參數(shù)名前加上“_”通配符耙旦,如:
func someFunction(_ firstParameterName: Int, secondParameterName: Int)
脱羡,調(diào)用時就可以someFunction(1, secondParameterName: 2)
。 - 聲明函數(shù)且函數(shù)有多個參數(shù)時免都,可以給某個參數(shù)設(shè)置默認(rèn)值锉罐;調(diào)用函數(shù)時就可以不傳這個參數(shù),如:
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12)
绕娘,調(diào)用時:someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6)
或someFunction(parameterWithoutDefault: 4)
脓规。 - 可變參數(shù)接受零個或多個指定類型的值,如:
func arithmeticMean(_ numbers: Double...) -> Double
险领,調(diào)用時:arithmeticMean(1, 2, 3, 4, 5)
侨舆。 - 函數(shù)參數(shù)默認(rèn)為常量。如果希望函數(shù)可以修改參數(shù)的值绢陌,并且希望這些更改在函數(shù)調(diào)用結(jié)束后仍然存在态罪,可以將該參數(shù)定義為in-out參數(shù),如:
func swapTwoInts(_ a: inout Int, _ b: inout Int)
下面,調(diào)用時,要聲明兩個var變量作為參數(shù)绩聘,并傳入函數(shù):swapTwoInts(&someInt, &anotherInt)
沥割,用“&+變量”作為參數(shù)。 - 在swift里凿菩,函數(shù)可以用其返回值作為類型机杜,所以函數(shù)可以作為另一個函數(shù)的返回值或者作為另一個函數(shù)的參數(shù);具體代碼請看文章里的內(nèi)容衅谷。
- 函數(shù)內(nèi)部可以嵌套另一個函數(shù)椒拗,嵌套函數(shù)默認(rèn)情況下對外界隱藏,但仍可以由其封閉函數(shù)調(diào)用和使用。 封閉函數(shù)還可以返回其嵌套函數(shù)之一蚀苛,以允許該嵌套函數(shù)在另一個作用域中使用在验。
最后一句話,喜歡的朋友可以給個??嗎堵未,你的鼓勵就是我的動力腋舌,嘿嘿~
參考文檔:Swift - Functions