2.0 翻譯+校對:dreamkidd
2.2 翻譯+校對:SketchK 2016-05-12
3.0 翻譯: crayygy 2016-09-12 校對: shanks 2016-09-27 3.0.1,shanks,2016-11-12
本頁包含內(nèi)容:
函數(shù)是一段完成特定任務(wù)的獨(dú)立代碼片段。你可以通過給函數(shù)命名來標(biāo)識某個(gè)函數(shù)的功能,這個(gè)名字可以被用來在需要的時(shí)候"調(diào)用"這個(gè)函數(shù)來完成它的任務(wù)。
Swift 統(tǒng)一的函數(shù)語法非常的靈活,可以用來表示任何函數(shù),包括從最簡單的沒有參數(shù)名字的 C 風(fēng)格函數(shù),到復(fù)雜的帶局部和外部參數(shù)名的 Objective-C 風(fēng)格函數(shù)。參數(shù)可以提供默認(rèn)值,以簡化函數(shù)調(diào)用。參數(shù)也可以既當(dāng)做傳入?yún)?shù),也當(dāng)做傳出參數(shù),也就是說,一旦函數(shù)執(zhí)行結(jié)束,傳入的參數(shù)值將被修改。
在 Swift 中,每個(gè)函數(shù)都有一個(gè)由函數(shù)的參數(shù)值類型和返回值類型組成的類型。你可以把函數(shù)類型當(dāng)做任何其他普通變量類型一樣處理,這樣就可以更簡單地把函數(shù)當(dāng)做別的函數(shù)的參數(shù),也可以從其他函數(shù)中返回函數(shù)。函數(shù)的定義可以寫在其他函數(shù)定義中,這樣可以在嵌套函數(shù)范圍內(nèi)實(shí)現(xiàn)功能封裝。
當(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
類型的返回值:
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}
所有的這些信息匯總起來成為函數(shù)的定義,并以 func
作為前綴。指定函數(shù)返回類型時(shí),用返回箭頭 ->
(一個(gè)連字符后跟一個(gè)右尖括號)后跟返回類型的名稱的方式來表示。
該定義描述了函數(shù)的功能,它期望接收什么作為參數(shù)和執(zhí)行結(jié)束時(shí)它返回的結(jié)果是什么類型。這樣的定義使得函數(shù)可以在別的地方以一種清晰的方式被調(diào)用:
print(greet(person: "Anna"))
// 打印 "Hello, Anna!"
print(greet(person: "Brian"))
// 打印 "Hello, Brian!"
調(diào)用 greet(person:)
函數(shù)時(shí),在圓括號中傳給它一個(gè) String
類型的實(shí)參,例如 greet(person: "Anna")
。正如上面所示,因?yàn)檫@個(gè)函數(shù)返回一個(gè) String
類型的值,所以greet
可以被包含在 print(_:separator:terminator:)
的調(diào)用中,用來輸出這個(gè)函數(shù)的返回值。
注意
print(_:separator:terminator:)
函數(shù)的第一個(gè)參數(shù)并沒有設(shè)置一個(gè)標(biāo)簽,而其他的參數(shù)因?yàn)橐呀?jīng)有了默認(rèn)值,因此是可選的。關(guān)于這些函數(shù)語法上的變化詳見下方關(guān)于 函數(shù)參數(shù)標(biāo)簽和參數(shù)名 以及 默認(rèn)參數(shù)值。
在 greet(person:)
的函數(shù)體中,先定義了一個(gè)新的名為 greeting
的 String
常量,同時(shí),把對 personName
的問候消息賦值給了 greeting
。然后用 return
關(guān)鍵字把這個(gè)問候返回出去。一旦 return greeting
被調(diào)用,該函數(shù)結(jié)束它的執(zhí)行并返回 greeting
的當(dāng)前值。
你可以用不同的輸入值多次調(diào)用 greet(person:)
。上面的例子展示的是用"Anna"
和"Brian"
調(diào)用的結(jié)果,該函數(shù)分別返回了不同的結(jié)果。
為了簡化這個(gè)函數(shù)的定義,可以將問候消息的創(chuàng)建和返回寫成一句:
func greetAgain(person: String) -> String {
return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// 打印 "Hello again, Anna!"
函數(shù)參數(shù)與返回值在 Swift 中非常的靈活。你可以定義任何類型的函數(shù),包括從只帶一個(gè)未名參數(shù)的簡單函數(shù)到復(fù)雜的帶有表達(dá)性參數(shù)名和不同參數(shù)選項(xiàng)的復(fù)雜函數(shù)。
函數(shù)可以沒有參數(shù)。下面這個(gè)函數(shù)就是一個(gè)無參數(shù)函數(shù),當(dāng)被調(diào)用時(shí),它返回固定的 String
消息:
func sayHelloWorld() -> String {
return "hello, world"
}
print(sayHelloWorld())
// 打印 "hello, world"
盡管這個(gè)函數(shù)沒有參數(shù),但是定義中在函數(shù)名后還是需要一對圓括號。當(dāng)被調(diào)用時(shí),也需要在函數(shù)名后寫一對圓括號。
函數(shù)可以有多種輸入?yún)?shù),這些參數(shù)被包含在函數(shù)的括號之中,以逗號分隔。
下面這個(gè)函數(shù)用一個(gè)人名和是否已經(jīng)打過招呼作為輸入,并返回對這個(gè)人的適當(dā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))
// 打印 "Hello again, Tim!"
你可以通過在括號內(nèi)使用逗號分隔來傳遞一個(gè)String
參數(shù)值和一個(gè)標(biāo)識為alreadyGreeted
的Bool
值,來調(diào)用greet(person:alreadyGreeted:)
函數(shù)。注意這個(gè)函數(shù)和上面greet(person:)
是不同的。雖然它們都有著同樣的名字greet
,但是greet(person:alreadyGreeted:)
函數(shù)需要兩個(gè)參數(shù),而greet(person:)
只需要一個(gè)參數(shù)。
函數(shù)可以沒有返回值。下面是 greet(person:)
函數(shù)的另一個(gè)版本,這個(gè)函數(shù)直接打印一個(gè)String
值,而不是返回它:
func greet(person: String) {
print("Hello, \(person)!")
}
greet(person: "Dave")
// 打印 "Hello, Dave!"
因?yàn)檫@個(gè)函數(shù)不需要返回值,所以這個(gè)函數(shù)的定義中沒有返回箭頭(->)和返回類型。
注意
嚴(yán)格上來說,雖然沒有返回值被定義,greet(person:)
函數(shù)依然返回了值。沒有定義返回類型的函數(shù)會返回一個(gè)特殊的Void
值。它其實(shí)是一個(gè)空的元組(tuple),沒有任何元素,可以寫成()。
被調(diào)用時(shí),一個(gè)函數(shù)的返回值可以被忽略:
func printAndCount(string: String) -> Int {
print(string)
return string.characters.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// 打印 "hello, world" 并且返回值 12
printWithoutCounting(string: "hello, world")
// 打印 "hello, world" 但是沒有返回任何值
第一個(gè)函數(shù) printAndCount(string:)
,輸出一個(gè)字符串并返回 Int
類型的字符數(shù)。第二個(gè)函數(shù) printWithoutCounting(string:)
調(diào)用了第一個(gè)函數(shù),但是忽略了它的返回值。當(dāng)?shù)诙€(gè)函數(shù)被調(diào)用時(shí),消息依然會由第一個(gè)函數(shù)輸出,但是返回值不會被用到。
注意:
返回值可以被忽略,但定義了有返回值的函數(shù)必須返回一個(gè)值,如果在函數(shù)定義底部沒有返回任何值,將導(dǎo)致編譯時(shí)錯誤(compile-time error)。
你可以用元組(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)
}
minMax(array:)
函數(shù)返回一個(gè)包含兩個(gè) Int
值的元組,這些值被標(biāo)記為 min
和 max
,以便查詢函數(shù)的返回值時(shí)可以通過名字訪問它們。
在 minMax(array:)
的函數(shù)體中,在開始的時(shí)候設(shè)置兩個(gè)工作變量 currentMin
和 currentMax
的值為數(shù)組中的第一個(gè)數(shù)。然后函數(shù)會遍歷數(shù)組中剩余的值并檢查該值是否比 currentMin
和 currentMax
更小或更大。最后數(shù)組中的最小值與最大值作為一個(gè)包含兩個(gè) Int
值的元組返回。
因?yàn)樵M的成員值已被命名,因此可以通過 .
語法來檢索找到的最小值與最大值:
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ù)中返回時(shí)命名,因?yàn)樗鼈兊拿忠呀?jīng)在函數(shù)返回類型中指定了。
如果函數(shù)返回的元組類型有可能整個(gè)元組都“沒有值”,你可以使用可選的( optional
) 元組返回類型反映整個(gè)元組可以是nil
的事實(shí)。你可以通過在元組類型的右括號后放置一個(gè)問號來定義一個(gè)可選元組,例如 (Int, Int)?
或 (String, Int, Bool)?
注意 可選元組類型如
(Int, Int)?
與元組包含可選類型如(Int?, Int?)
是不同的.可選的元組類型,整個(gè)元組是可選的,而不只是元組中的每個(gè)元素值。
前面的 minMax(array:)
函數(shù)返回了一個(gè)包含兩個(gè) Int
值的元組。但是函數(shù)不會對傳入的數(shù)組執(zhí)行任何安全檢查,如果 array
參數(shù)是一個(gè)空數(shù)組,如上定義的 minMax(array:)
在試圖訪問 array[0]
時(shí)會觸發(fā)一個(gè)運(yùn)行時(shí)錯誤(runtime error)。
為了安全地處理這個(gè)“空數(shù)組”問題,將 minMax(array:)
函數(shù)改寫為使用可選元組返回類型,并且當(dāng)數(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ù)返回的是一個(gè)存在的元組值還是 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"
每個(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ù)名稱前指定它的參數(shù)標(biāo)簽,中間以空格分隔:
func someFunction(argumentLabel parameterName: Int) {
// 在函數(shù)體內(nèi),parameterName 代表參數(shù)值
}
這個(gè)版本的 greet(person:)
函數(shù),接收一個(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"))
// 打印 "Hello Bill! Glad you could visit from Cupertino."
參數(shù)標(biāo)簽的使用能夠讓一個(gè)函數(shù)在調(diào)用時(shí)更有表達(dá)力,更類似自然語言,并且仍保持了函數(shù)內(nèi)部的可讀性以及清晰的意圖。
如果你不希望為某個(gè)參數(shù)添加一個(gè)標(biāo)簽,可以使用一個(gè)下劃線(_
)來代替一個(gè)明確的參數(shù)標(biāo)簽。
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// 在函數(shù)體內(nèi),firstParameterName 和 secondParameterName 代表參數(shù)中的第一個(gè)和第二個(gè)參數(shù)值
}
someFunction(1, secondParameterName: 2)
如果一個(gè)參數(shù)有一個(gè)標(biāo)簽,那么在調(diào)用的時(shí)候必須使用標(biāo)簽來標(biāo)記這個(gè)參數(shù)。
你可以在函數(shù)體中通過給參數(shù)賦值來為任意一個(gè)參數(shù)定義默認(rèn)值(Deafult Value)。當(dāng)默認(rèn)值被定義后,調(diào)用這個(gè)函數(shù)時(shí)可以忽略這個(gè)參數(shù)。
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
// 如果你在調(diào)用時(shí)候不傳第二個(gè)參數(shù),parameterWithDefault 會值為 12 傳入到函數(shù)體中。
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault = 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault = 12
將不帶有默認(rèn)值的參數(shù)放在函數(shù)參數(shù)列表的最前。一般來說,沒有默認(rèn)值的參數(shù)更加的重要,將不帶默認(rèn)值的參數(shù)放在最前保證在函數(shù)調(diào)用時(shí),非默認(rèn)參數(shù)的順序是一致的,同時(shí)也使得相同的函數(shù)在不同情況下調(diào)用時(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)
}
arithmeticMean(1, 2, 3, 4, 5)
// 返回 3.0, 是這 5 個(gè)數(shù)的平均數(shù)。
arithmeticMean(3, 8.25, 18.75)
// 返回 10.0, 是這 3 個(gè)數(shù)的平均數(shù)。
注意:
一個(gè)函數(shù)最多只能擁有一個(gè)可變參數(shù)。
函數(shù)參數(shù)默認(rèn)是常量。試圖在函數(shù)體中更改參數(shù)值將會導(dǎo)致編譯錯誤(compile-time error)。這意味著你不能錯誤地更改參數(shù)值。如果你想要一個(gè)函數(shù)可以修改參數(shù)的值,并且想要在這些修改在函數(shù)調(diào)用結(jié)束后仍然存在,那么就應(yīng)該把這個(gè)參數(shù)定義為輸入輸出參數(shù)(In-Out Parameters)。
定義一個(gè)輸入輸出參數(shù)時(shí),在參數(shù)定義前加 inout
關(guān)鍵字。一個(gè)輸入輸出參數(shù)
有傳入函數(shù)的值,這個(gè)值被函數(shù)修改,然后被傳出函數(shù),替換原來的值。想獲取更多的關(guān)于輸入輸出參數(shù)的細(xì)節(jié)和相關(guān)的編譯器優(yōu)化,請查看輸入輸出參數(shù)一節(jié)。
你只能傳遞變量給輸入輸出參數(shù)。你不能傳入常量或者字面量,因?yàn)檫@些量是不能被修改的。當(dāng)傳入的參數(shù)作為輸入輸出參數(shù)時(shí),需要在參數(shù)名前加 &
符,表示這個(gè)值可以被函數(shù)修改。
注意 輸入輸出參數(shù)不能有默認(rèn)值,而且可變參數(shù)不能用
inout
標(biāo)記。
下例中,swapTwoInts(_:_:)
函數(shù)有兩個(gè)分別叫做 a
和 b
的輸入輸出參數(shù):
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoInts(_:_:)
函數(shù)簡單地交換 a
與 b
的值。該函數(shù)先將 a
的值存到一個(gè)臨時(shí)常量 temporaryA
中,然后將 b
的值賦給 a
,最后將 temporaryA
賦值給 b
。
你可以用兩個(gè) Int
型的變量來調(diào)用 swapTwoInts(_:_:)
。需要注意的是,someInt
和 anotherInt
在傳入 swapTwoInts(_:_:)
函數(shù)前,都加了 &
的前綴:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// 打印 "someInt is now 107, and anotherInt is now 3"
從上面這個(gè)例子中,我們可以看到 someInt
和 anotherInt
的原始值在 swapTwoInts(_:_:)
函數(shù)中被修改,盡管它們的定義在函數(shù)體外。
注意:
輸入輸出參數(shù)和返回值是不一樣的。上面的swapTwoInts
函數(shù)并沒有定義任何返回值,但仍然修改了someInt
和anotherInt
的值。輸入輸出參數(shù)是函數(shù)對函數(shù)體外產(chǎn)生影響的另一種方式。
每個(gè)函數(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
}
這個(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
型的值?!薄?/p>
下面是另一個(gè)例子,一個(gè)沒有參數(shù),也沒有返回值的函數(shù):
func printHelloWorld() {
print("hello, world")
}
這個(gè)函數(shù)的類型是:() -> Void
,或者叫“沒有參數(shù),并返回 Void
類型的函數(shù)”。
在 Swift 中,使用函數(shù)類型就像使用其他類型一樣。例如,你可以定義一個(gè)類型為函數(shù)的常量或變量,并將適當(dāng)?shù)暮瘮?shù)賦值給它:
var mathFunction: (Int, Int) -> Int = addTwoInts
這段代碼可以被解讀為:
”定義一個(gè)叫做 mathFunction
的變量,類型是‘一個(gè)有兩個(gè) Int
型的參數(shù)并返回一個(gè) Int
型的值的函數(shù)’,并讓這個(gè)新變量指向 addTwoInts
函數(shù)”。
addTwoInts
和 mathFunction
有同樣的類型,所以這個(gè)賦值過程在 Swift 類型檢查(type-check)中是允許的。
現(xiàn)在,你可以用 mathFunction
來調(diào)用被賦值的函數(shù)了:
print("Result: \(mathFunction(2, 3))")
// Prints "Result: 5"
有相同匹配類型的不同函數(shù)可以被賦值給同一個(gè)變量,就像非函數(shù)類型的變量一樣:
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// Prints "Result: 6"
就像其他類型一樣,當(dāng)賦值一個(gè)函數(shù)給常量或變量時(shí),你可以讓 Swift 來推斷其函數(shù)類型:
let anotherMathFunction = addTwoInts
// anotherMathFunction 被推斷為 (Int, Int) -> Int 類型
你可以用 (Int, Int) -> Int
這樣的函數(shù)類型作為另一個(gè)函數(shù)的參數(shù)類型。這樣你可以將函數(shù)的一部分實(shí)現(xiàn)留給函數(shù)的調(diào)用者來提供。
下面是另一個(gè)例子,正如上面的函數(shù)一樣,同樣是輸出某種數(shù)學(xué)運(yùn)算結(jié)果:
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ù)的輸入值。
當(dāng) printMathResult(_:_:_:)
被調(diào)用時(shí),它被傳入 addTwoInts
函數(shù)和整數(shù) 3
和 5
。它用傳入 3
和 5
調(diào)用 addTwoInts
,并輸出結(jié)果:8
。
printMathResult(_:_:_:)
函數(shù)的作用就是輸出另一個(gè)適當(dāng)類型的數(shù)學(xué)函數(shù)的調(diào)用結(jié)果。它不關(guān)心傳入函數(shù)是如何實(shí)現(xiàn)的,只關(guān)心傳入的函數(shù)是不是一個(gè)正確的類型。這使得 printMathResult(_:_:_:)
能以一種類型安全(type-safe)的方式將一部分功能轉(zhuǎn)給調(diào)用者實(shí)現(xiàn)。
你可以用函數(shù)類型作為另一個(gè)函數(shù)的返回類型。你需要做的是在返回箭頭(->)后寫一個(gè)完整的函數(shù)類型。
下面的這個(gè)例子中定義了兩個(gè)簡單函數(shù),分別是 stepForward(_:)
和 stepBackward(_:)
。stepForward(_:)
函數(shù)返回一個(gè)比輸入值大 1
的值。stepBackward(_:)
函數(shù)返回一個(gè)比輸入值小 1
的值。這兩個(gè)函數(shù)的類型都是 (Int) -> Int
:
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
如下名為 chooseStepFunction(backward:)
的函數(shù),它的返回類型是 (Int) -> Int
類型的函數(shù)。chooseStepFunction(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(_:)
返回 stepBackward(_:)
函數(shù)。一個(gè)指向返回的函數(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!
到目前為止本章中你所見到的所有函數(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!