這里的教程為Swift官方教程中文版。

函數(shù)(Functions)


1.0 翻譯:honghaoz 校對:LunaticM

2.0 翻譯+校對:dreamkidd

2.1 翻譯:DianQK 定稿:shanks

2.2 翻譯+校對:SketchK 2016-05-12

3.0 翻譯: crayygy 2016-09-12 校對: shanks 2016-09-27 3.0.1,shanks,2016-11-12

4.0 校對:kemchenj 2017-09-21

本頁包含內(nèi)容:

函數(shù)是一段完成特定任務的獨立代碼片段。你可以通過給函數(shù)命名來標識某個函數(shù)的功能,這個名字可以被用來在需要的時候"調(diào)用"這個函數(shù)來完成它的任務。

Swift 統(tǒng)一的函數(shù)語法非常的靈活,可以用來表示任何函數(shù),包括從最簡單的沒有參數(shù)名字的 C 風格函數(shù),到復雜的帶局部和外部參數(shù)名的 Objective-C 風格函數(shù)。參數(shù)可以提供默認值,以簡化函數(shù)調(diào)用。參數(shù)也可以既當做傳入?yún)?shù),也當做傳出參數(shù),也就是說,一旦函數(shù)執(zhí)行結(jié)束,傳入的參數(shù)值將被修改。

在 Swift 中,每個函數(shù)都有一個由函數(shù)的參數(shù)值類型和返回值類型組成的類型。你可以把函數(shù)類型當做任何其他普通變量類型一樣處理,這樣就可以更簡單地把函數(shù)當做別的函數(shù)的參數(shù),也可以從其他函數(shù)中返回函數(shù)。函數(shù)的定義可以寫在其他函數(shù)定義中,這樣可以在嵌套函數(shù)范圍內(nèi)實現(xiàn)功能封裝。

函數(shù)的定義與調(diào)用

當你定義一個函數(shù)時,你可以定義一個或多個有名字和類型的值,作為函數(shù)的輸入,稱為參數(shù),也可以定義某種類型的值作為函數(shù)執(zhí)行結(jié)束時的輸出,稱為返回類型。

每個函數(shù)有個函數(shù)名,用來描述函數(shù)執(zhí)行的任務。要使用一個函數(shù)時,用函數(shù)名來“調(diào)用”這個函數(shù),并傳給它匹配的輸入值(稱作 實參 )。函數(shù)的實參必須與函數(shù)參數(shù)表里參數(shù)的順序一致。

下面例子中的函數(shù)的名字是greet(person:),之所以叫這個名字,是因為這個函數(shù)用一個人的名字當做輸入,并返回向這個人問候的語句。為了完成這個任務,你需要定義一個輸入?yún)?shù)——一個叫做 personString 值,和一個包含給這個人問候語的 String 類型的返回值:

func greet(person: String) -> String {
    let greeting = "Hello, " + person + "!"
    return greeting
}

所有的這些信息匯總起來成為函數(shù)的定義,并以 func 作為前綴。指定函數(shù)返回類型時,用返回箭頭 ->(一個連字符后跟一個右尖括號)后跟返回類型的名稱的方式來表示。

該定義描述了函數(shù)的功能,它期望接收什么作為參數(shù)和執(zhí)行結(jié)束時它返回的結(jié)果是什么類型。這樣的定義使得函數(shù)可以在別的地方以一種清晰的方式被調(diào)用:

print(greet(person: "Anna"))
// 打印 "Hello, Anna!"
print(greet(person: "Brian"))
// 打印 "Hello, Brian!"

調(diào)用 greet(person:) 函數(shù)時,在圓括號中傳給它一個 String 類型的實參,例如 greet(person: "Anna")。正如上面所示,因為這個函數(shù)返回一個 String 類型的值,所以greet 可以被包含在 print(_:separator:terminator:) 的調(diào)用中,用來輸出這個函數(shù)的返回值。

注意
print(_:separator:terminator:) 函數(shù)的第一個參數(shù)并沒有設置一個標簽,而其他的參數(shù)因為已經(jīng)有了默認值,因此是可選的。關于這些函數(shù)語法上的變化詳見下方關于 函數(shù)參數(shù)標簽和參數(shù)名 以及 默認參數(shù)值。

greet(person:) 的函數(shù)體中,先定義了一個新的名為 greetingString 常量,同時,把對 personName 的問候消息賦值給了 greeting 。然后用 return 關鍵字把這個問候返回出去。一旦 return greeting 被調(diào)用,該函數(shù)結(jié)束它的執(zhí)行并返回 greeting 的當前值。

你可以用不同的輸入值多次調(diào)用 greet(person:)。上面的例子展示的是用"Anna""Brian"調(diào)用的結(jié)果,該函數(shù)分別返回了不同的結(jié)果。

為了簡化這個函數(shù)的定義,可以將問候消息的創(chuàng)建和返回寫成一句:

func greetAgain(person: String) -> String {
    return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// 打印 "Hello again, Anna!"

函數(shù)參數(shù)與返回值

函數(shù)參數(shù)與返回值在 Swift 中非常的靈活。你可以定義任何類型的函數(shù),包括從只帶一個未名參數(shù)的簡單函數(shù)到復雜的帶有表達性參數(shù)名和不同參數(shù)選項的復雜函數(shù)。

無參數(shù)函數(shù)

函數(shù)可以沒有參數(shù)。下面這個函數(shù)就是一個無參數(shù)函數(shù),當被調(diào)用時,它返回固定的 String 消息:

func sayHelloWorld() -> String {
    return "hello, world"
}
print(sayHelloWorld())
// 打印 "hello, world"

盡管這個函數(shù)沒有參數(shù),但是定義中在函數(shù)名后還是需要一對圓括號。當被調(diào)用時,也需要在函數(shù)名后寫一對圓括號。

多參數(shù)函數(shù)

函數(shù)可以有多種輸入?yún)?shù),這些參數(shù)被包含在函數(shù)的括號之中,以逗號分隔。

下面這個函數(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))
// 打印 "Hello again, Tim!"

你可以通過在括號內(nèi)使用逗號分隔來傳遞一個String參數(shù)值和一個標識為alreadyGreetedBool值,來調(diào)用greet(person:alreadyGreeted:)函數(shù)。注意這個函數(shù)和上面greet(person:)是不同的。雖然它們都有著同樣的名字greet,但是greet(person:alreadyGreeted:)函數(shù)需要兩個參數(shù),而greet(person:)只需要一個參數(shù)。

無返回值函數(shù)

函數(shù)可以沒有返回值。下面是 greet(person:) 函數(shù)的另一個版本,這個函數(shù)直接打印一個String值,而不是返回它:

func greet(person: String) {
    print("Hello, \(person)!")
}
greet(person: "Dave")
// 打印 "Hello, Dave!"

因為這個函數(shù)不需要返回值,所以這個函數(shù)的定義中沒有返回箭頭(->)和返回類型。

注意
嚴格上來說,雖然沒有返回值被定義,greet(person:) 函數(shù)依然返回了值。沒有定義返回類型的函數(shù)會返回一個特殊的Void值。它其實是一個空的元組(tuple),沒有任何元素,可以寫成()。

被調(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")
// 打印 "hello, world" 并且返回值 12
printWithoutCounting(string: "hello, world")
// 打印 "hello, world" 但是沒有返回任何值

第一個函數(shù) printAndCount(string:),輸出一個字符串并返回 Int 類型的字符數(shù)。第二個函數(shù) printWithoutCounting(string:)調(diào)用了第一個函數(shù),但是忽略了它的返回值。當?shù)诙€函數(shù)被調(diào)用時,消息依然會由第一個函數(shù)輸出,但是返回值不會被用到。

注意:
返回值可以被忽略,但定義了有返回值的函數(shù)必須返回一個值,如果在函數(shù)定義底部沒有返回任何值,將導致編譯時錯誤(compile-time error)。

多重返回值函數(shù)

你可以用元組(tuple)類型讓多個值作為一個復合值從函數(shù)中返回。

下例中定義了一個名為 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ù)返回一個包含兩個 Int 值的元組,這些值被標記為 minmax ,以便查詢函數(shù)的返回值時可以通過名字訪問它們。

minMax(array:) 的函數(shù)體中,在開始的時候設置兩個工作變量 currentMincurrentMax 的值為數(shù)組中的第一個數(shù)。然后函數(shù)會遍歷數(shù)組中剩余的值并檢查該值是否比 currentMincurrentMax 更小或更大。最后數(shù)組中的最小值與最大值作為一個包含兩個 Int 值的元組返回。

因為元組的成員值已被命名,因此可以通過 . 語法來檢索找到的最小值與最大值:

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ù)中返回時命名,因為它們的名字已經(jīng)在函數(shù)返回類型中指定了。

可選元組返回類型

如果函數(shù)返回的元組類型有可能整個元組都“沒有值”,你可以使用可選的( optional ) 元組返回類型反映整個元組可以是nil的事實。你可以通過在元組類型的右括號后放置一個問號來定義一個可選元組,例如 (Int, Int)?(String, Int, Bool)?

注意 可選元組類型如 (Int, Int)? 與元組包含可選類型如 (Int?, Int?) 是不同的.可選的元組類型,整個元組是可選的,而不只是元組中的每個元素值。

前面的 minMax(array:) 函數(shù)返回了一個包含兩個 Int 值的元組。但是函數(shù)不會對傳入的數(shù)組執(zhí)行任何安全檢查,如果 array 參數(shù)是一個空數(shù)組,如上定義的 minMax(array:) 在試圖訪問 array[0] 時會觸發(fā)一個運行時錯誤(runtime error)。

為了安全地處理這個“空數(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)")
}
// 打印 "min is -6 and max is 109"

函數(shù)參數(shù)標簽和參數(shù)名稱

每個函數(shù)參數(shù)都有一個參數(shù)標簽( argument label )以及一個參數(shù)名稱( parameter name )。參數(shù)標簽在調(diào)用函數(shù)的時候使用;調(diào)用的時候需要將函數(shù)的參數(shù)標簽寫在對應的參數(shù)前面。參數(shù)名稱在函數(shù)的實現(xiàn)中使用。默認情況下,函數(shù)參數(shù)使用參數(shù)名稱來作為它們的參數(shù)標簽。

func someFunction(firstParameterName: Int, secondParameterName: Int) {
    // 在函數(shù)體內(nèi),firstParameterName 和 secondParameterName 代表參數(shù)中的第一個和第二個參數(shù)值
}
someFunction(firstParameterName: 1, secondParameterName: 2)

所有的參數(shù)都必須有一個獨一無二的名字。雖然多個參數(shù)擁有同樣的參數(shù)標簽是可能的,但是一個唯一的函數(shù)標簽能夠使你的代碼更具可讀性。

指定參數(shù)標簽

你可以在參數(shù)名稱前指定它的參數(shù)標簽,中間以空格分隔:

func someFunction(argumentLabel parameterName: Int) {
    // 在函數(shù)體內(nèi),parameterName 代表參數(shù)值
}

這個版本的 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"))
// 打印 "Hello Bill! Glad you could visit from Cupertino."

參數(shù)標簽的使用能夠讓一個函數(shù)在調(diào)用時更有表達力,更類似自然語言,并且仍保持了函數(shù)內(nèi)部的可讀性以及清晰的意圖。

忽略參數(shù)標簽

如果你不希望為某個參數(shù)添加一個標簽,可以使用一個下劃線(_)來代替一個明確的參數(shù)標簽。

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
     // 在函數(shù)體內(nèi),firstParameterName 和 secondParameterName 代表參數(shù)中的第一個和第二個參數(shù)值
}
someFunction(1, secondParameterName: 2)

如果一個參數(shù)有一個標簽,那么在調(diào)用的時候必須使用標簽來標記這個參數(shù)。

默認參數(shù)值

你可以在函數(shù)體中通過給參數(shù)賦值來為任意一個參數(shù)定義默認值(Deafult Value)。當默認值被定義后,調(diào)用這個函數(shù)時可以忽略這個參數(shù)。

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
    // 如果你在調(diào)用時候不傳第二個參數(shù),parameterWithDefault 會值為 12 傳入到函數(shù)體中。
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault = 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault = 12

將不帶有默認值的參數(shù)放在函數(shù)參數(shù)列表的最前。一般來說,沒有默認值的參數(shù)更加的重要,將不帶默認值的參數(shù)放在最前保證在函數(shù)調(diào)用時,非默認參數(shù)的順序是一致的,同時也使得相同的函數(shù)在不同情況下調(diào)用時顯得更為清晰。

可變參數(shù)

一個可變參數(shù)(variadic parameter)可以接受零個或多個值。函數(shù)調(diào)用時,你可以用可變參數(shù)來指定函數(shù)參數(shù)可以被傳入不確定數(shù)量的輸入值。通過在變量類型名后面加入(...)的方式來定義可變參數(shù)。

可變參數(shù)的傳入值在函數(shù)體中變?yōu)榇祟愋偷囊粋€數(shù)組。例如,一個叫做 numbersDouble... 型可變參數(shù),在函數(shù)體內(nèi)可以當做一個叫 numbers[Double] 型的數(shù)組常量。

下面的這個函數(shù)用來計算一組任意長度數(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 個數(shù)的平均數(shù)。
arithmeticMean(3, 8.25, 18.75)
// 返回 10.0, 是這 3 個數(shù)的平均數(shù)。

注意:
一個函數(shù)最多只能擁有一個可變參數(shù)。

輸入輸出參數(shù)

函數(shù)參數(shù)默認是常量。試圖在函數(shù)體中更改參數(shù)值將會導致編譯錯誤(compile-time error)。這意味著你不能錯誤地更改參數(shù)值。如果你想要一個函數(shù)可以修改參數(shù)的值,并且想要在這些修改在函數(shù)調(diào)用結(jié)束后仍然存在,那么就應該把這個參數(shù)定義為輸入輸出參數(shù)(In-Out Parameters)。

定義一個輸入輸出參數(shù)時,在參數(shù)定義前加 inout 關鍵字。一個輸入輸出參數(shù)有傳入函數(shù)的值,這個值被函數(shù)修改,然后被傳出函數(shù),替換原來的值。想獲取更多的關于輸入輸出參數(shù)的細節(jié)和相關的編譯器優(yōu)化,請查看輸入輸出參數(shù)一節(jié)。

你只能傳遞變量給輸入輸出參數(shù)。你不能傳入常量或者字面量,因為這些量是不能被修改的。當傳入的參數(shù)作為輸入輸出參數(shù)時,需要在參數(shù)名前加 & 符,表示這個值可以被函數(shù)修改。

注意 輸入輸出參數(shù)不能有默認值,而且可變參數(shù)不能用 inout 標記。

下例中,swapTwoInts(_:_:) 函數(shù)有兩個分別叫做 ab 的輸入輸出參數(shù):

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

swapTwoInts(_:_:) 函數(shù)簡單地交換 ab 的值。該函數(shù)先將 a 的值存到一個臨時常量 temporaryA 中,然后將 b 的值賦給 a,最后將 temporaryA 賦值給 b

你可以用兩個 Int 型的變量來調(diào)用 swapTwoInts(_:_:)。需要注意的是,someIntanotherInt 在傳入 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"

從上面這個例子中,我們可以看到 someIntanotherInt 的原始值在 swapTwoInts(_:_:) 函數(shù)中被修改,盡管它們的定義在函數(shù)體外。

注意:
輸入輸出參數(shù)和返回值是不一樣的。上面的 swapTwoInts 函數(shù)并沒有定義任何返回值,但仍然修改了 someIntanotherInt 的值。輸入輸出參數(shù)是函數(shù)對函數(shù)體外產(chǎn)生影響的另一種方式。

函數(shù)類型

每個函數(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ù)學函數(shù):addTwoIntsmultiplyTwoInts。這兩個函數(shù)都接受兩個 Int 值, 返回一個 Int 值。

這兩個函數(shù)的類型是 (Int, Int) -> Int,可以解讀為“這個函數(shù)類型有兩個 Int 型的參數(shù)并返回一個 Int 型的值。”。

下面是另一個例子,一個沒有參數(shù),也沒有返回值的函數(shù):

func printHelloWorld() {
    print("hello, world")
}

這個函數(shù)的類型是:() -> Void,或者叫“沒有參數(shù),并返回 Void 類型的函數(shù)”。

使用函數(shù)類型

在 Swift 中,使用函數(shù)類型就像使用其他類型一樣。例如,你可以定義一個類型為函數(shù)的常量或變量,并將適當?shù)暮瘮?shù)賦值給它:

var mathFunction: (Int, Int) -> Int = addTwoInts

這段代碼可以被解讀為:

”定義一個叫做 mathFunction 的變量,類型是‘一個有兩個 Int 型的參數(shù)并返回一個 Int 型的值的函數(shù)’,并讓這個新變量指向 addTwoInts 函數(shù)”。

addTwoIntsmathFunction 有同樣的類型,所以這個賦值過程在 Swift 類型檢查(type-check)中是允許的。

現(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 被推斷為 (Int, Int) -> Int 類型

函數(shù)類型作為參數(shù)類型

你可以用 (Int, Int) -> Int 這樣的函數(shù)類型作為另一個函數(shù)的參數(shù)類型。這樣你可以將函數(shù)的一部分實現(xiàn)留給函數(shù)的調(diào)用者來提供。

下面是另一個例子,正如上面的函數(shù)一樣,同樣是輸出某種數(shù)學運算結(jié)果:

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// 打印 "Result: 8"

這個例子定義了 printMathResult(_:_:_:) 函數(shù),它有三個參數(shù):第一個參數(shù)叫 mathFunction,類型是 (Int, Int) -> Int,你可以傳入任何這種類型的函數(shù);第二個和第三個參數(shù)叫 ab,它們的類型都是 Int,這兩個值作為已給出的函數(shù)的輸入值。

printMathResult(_:_:_:) 被調(diào)用時,它被傳入 addTwoInts 函數(shù)和整數(shù) 35。它用傳入 35 調(diào)用 addTwoInts,并輸出結(jié)果:8。

printMathResult(_:_:_:) 函數(shù)的作用就是輸出另一個適當類型的數(shù)學函數(shù)的調(diào)用結(jié)果。它不關心傳入函數(shù)是如何實現(xiàn)的,只關心傳入的函數(shù)是不是一個正確的類型。這使得 printMathResult(_:_:_:) 能以一種類型安全(type-safe)的方式將一部分功能轉(zhuǎn)給調(diào)用者實現(xiàn)。

函數(shù)類型作為返回類型

你可以用函數(shù)類型作為另一個函數(shù)的返回類型。你需要做的是在返回箭頭(->)后寫一個完整的函數(shù)類型。

下面的這個例子中定義了兩個簡單函數(shù),分別是 stepForward(_:)stepBackward(_:)。stepForward(_:)函數(shù)返回一個比輸入值大 1 的值。stepBackward(_:) 函數(shù)返回一個比輸入值小 1 的值。這兩個函數(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:) 來獲得兩個函數(shù)其中的一個:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero 現(xiàn)在指向 stepBackward() 函數(shù)。

上面這個例子中計算出從 currentValue 逐漸接近到0是需要向正數(shù)走還是向負數(shù)走。currentValue 的初始值是 3,這意味著 currentValue > 0 為真(true),這將使得 chooseStepFunction(_:) 返回 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!

嵌套函數(shù)

到目前為止本章中你所見到的所有函數(shù)都叫全局函數(shù)(global functions),它們定義在全局域中。你也可以把函數(shù)定義在別的函數(shù)體中,稱作 嵌套函數(shù)(nested functions)。

默認情況下,嵌套函數(shù)是對外界不可見的,但是可以被它們的外圍函數(shù)(enclosing function)調(diào)用。一個外圍函數(shù)也可以返回它的某一個嵌套函數(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!
? 控制流 閉包 ?
?