6.函數(shù)[Functions]

[The Swift Programming Language 中文版]
本頁包含內(nèi)容:

函數(shù)定義與調(diào)用(Defining and Calling Functions)
函數(shù)參數(shù)與返回值(Function Parameters and Return Values)
函數(shù)參數(shù)名稱(Function Parameter Names)
函數(shù)類型(Function Types)
嵌套函數(shù)(Nested Functions)

函數(shù)是用來完成特定任務(wù)的獨立的代碼塊非洲。你給一個函數(shù)起一個合適的名字,用來標識函數(shù)做什么,并且當(dāng)函數(shù)需要執(zhí)行的時候尿褪,這個名字會被用于“調(diào)用”函數(shù)。

Swift 統(tǒng)一的函數(shù)語法足夠靈活,可以用來表示任何函數(shù)洼冻,包括從最簡單的沒有參數(shù)名字的 C 風(fēng)格函數(shù),到復(fù)雜的帶局部和外部參數(shù)名的 Objective-C 風(fēng)格函數(shù)隅很。參數(shù)可以提供默認值撞牢,以簡化函數(shù)調(diào)用。參數(shù)也可以既當(dāng)做傳入?yún)?shù)叔营,也當(dāng)做傳出參數(shù)屋彪,也就是說,一旦函數(shù)執(zhí)行結(jié)束绒尊,傳入的參數(shù)值可以被修改畜挥。

在 Swift 中,每個函數(shù)都有一種類型婴谱,包括函數(shù)的參數(shù)值類型和返回值類型蟹但。你可以把函數(shù)類型當(dāng)做任何其他普通變量類型一樣處理,這樣就可以更簡單地把函數(shù)當(dāng)做別的函數(shù)的參數(shù)谭羔,也可以從其他函數(shù)中返回函數(shù)华糖。函數(shù)的定義可以寫在其他函數(shù)定義中,這樣可以在嵌套函數(shù)范圍內(nèi)實現(xiàn)功能封裝口糕。

函數(shù)的定義與調(diào)用(Defining and Calling Functions)
當(dāng)你定義一個函數(shù)時缅阳,你可以定義一個或多個有名字和類型的值,作為函數(shù)的輸入(稱為參數(shù)景描,parameters)十办,也可以定義某種類型的值作為函數(shù)執(zhí)行結(jié)束的輸出(稱為返回類型,return type)超棺。

每個函數(shù)有個函數(shù)名向族,用來描述函數(shù)執(zhí)行的任務(wù)。要使用一個函數(shù)時棠绘,你用函數(shù)名“調(diào)用”件相,并傳給它匹配的輸入值(稱作實參再扭,arguments)。一個函數(shù)的實參必須與函數(shù)參數(shù)表里參數(shù)的順序一致夜矗。

在下面例子中的函數(shù)叫做"sayHello(_:)"泛范,之所以叫這個名字,是因為這個函數(shù)用一個人的名字當(dāng)做輸入,并返回給這個人的問候語罢荡。為了完成這個任務(wù)对扶,你定義一個輸入?yún)?shù)-一個叫做 personName 的 String 值,和一個包含給這個人問候語的 String 類型的返回值:

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

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

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

print(sayHello("Anna"))
// prints "Hello, Anna!"
print(sayHello("Brian"))
// prints "Hello, Brian!"

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

在 sayHello(_:) 的函數(shù)體中,先定義了一個新的名為 greeting 的 String 常量貌笨,同時襟沮,把對 personName 的問候消息賦值給了 greeting 昌腰。然后用 return 關(guān)鍵字把這個問候返回出去遭商。一旦 return greeting 被調(diào)用捅伤,該函數(shù)結(jié)束它的執(zhí)行并返回 greeting 的當(dāng)前值。

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

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

func sayHelloAgain(personName: String) -> String {
    return "Hello again, " + personName + "!"
}
print(sayHelloAgain("Anna"))
// prints "Hello again, Anna!"

函數(shù)參數(shù)與返回值(Function Parameters and Return Values)
函數(shù)參數(shù)與返回值在 Swift 中極為靈活。你可以定義任何類型的函數(shù)屿良,包括從只帶一個未名參數(shù)的簡單函數(shù)到復(fù)雜的帶有表達性參數(shù)名和不同參數(shù)選項的復(fù)雜函數(shù)尘惧。

無參函數(shù)(Functions Without Parameters)

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

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

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

多參數(shù)函數(shù) (Functions With Multiple Parameters)

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

這個函數(shù)用一個人名和是否已經(jīng)打過招呼作為輸入悴务,并返回對這個人的適當(dāng)問候語:

func sayHello(personName: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return sayHelloAgain(personName)
    } else {
        return sayHello(personName)
    }
}
print(sayHello("Tim", alreadyGreeted: true))
// prints "Hello again, Tim!"

你通過在括號內(nèi)傳遞一個String參數(shù)值和一個標識為alreadyGreeted的Bool值讯檐,使用逗號分隔來調(diào)用sayHello(_:alreadyGreeted:)函數(shù)。

當(dāng)調(diào)用超過一個參數(shù)的函數(shù)時叨恨,第一個參數(shù)后的參數(shù)根據(jù)其對應(yīng)的參數(shù)名稱標記痒钝,函數(shù)參數(shù)命名在函數(shù)參數(shù)名稱(Function Parameter Names)有更詳細的描述痢毒。

無返回值函數(shù)(Functions Without Return Values)

函數(shù)可以沒有返回值。下面是 sayHello(:) 函數(shù)的另一個版本栋荸,叫 sayGoodbye(:)蒸其,這個函數(shù)直接輸出 String 值库快,而不是返回它:

func sayGoodbye(personName: String) {
    print("Goodbye, \(personName)!")
}
sayGoodbye("Dave")
// prints "Goodbye, Dave!"

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

注意
嚴格上來說,雖然沒有返回值被定義兄墅,sayGoodbye(_:) 函數(shù)依然返回了值隙咸。沒有定義返回類型的函數(shù)會返回特殊的值,叫 Void藏否。它其實是一個空的元組(tuple)充包,沒有任何元素基矮,可以寫成()。
被調(diào)用時本砰,一個函數(shù)的返回值可以被忽略:

func printAndCount(stringToPrint: String) -> Int {
    print(stringToPrint)
    return stringToPrint.characters.count
}
func printWithoutCounting(stringToPrint: String) {
    printAndCount(stringToPrint)
}
printAndCount("hello, world")
// prints "hello, world" and returns a value of 12
printWithoutCounting("hello, world")
// prints "hello, world" but does not return a value

第一個函數(shù) printAndCount(_:)灌具,輸出一個字符串并返回 Int 類型的字符數(shù)譬巫。第二個函數(shù) printWithoutCounting調(diào)用了第一個函數(shù)芦昔,但是忽略了它的返回值。當(dāng)?shù)诙€函數(shù)被調(diào)用時珠十,消息依然會由第一個函數(shù)輸出凭豪,但是返回值不會被用到。

注意
返回值可以被忽略孔厉,但定義了有返回值的函數(shù)必須返回一個值撰豺,如果在函數(shù)定義底部沒有返回任何值拼余,將導(dǎo)致編譯錯誤(compile-time error)匙监。

多重返回值函數(shù)(Functions with Multiple Return Values)

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

下面的這個例子中梭纹,定義了一個名為minMax(_:)的函數(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(_:)函數(shù)返回一個包含兩個Int值的元組诡宗,這些值被標記為min和max塔沃,以便查詢函數(shù)的返回值時可以通過名字訪問它們阳谍。

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

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

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

可選元組返回類型(Optional Tuple Return Types)

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

注意
可選元組類型如(Int, Int)?與元組包含可選類型如(Int?, Int?)是不同的.可選的元組類型洁段,整個元組是可選的共郭,而不只是元組中的每個元素值除嘹。
前面的minMax(:)函數(shù)返回了一個包含兩個Int值的元組。但是函數(shù)不會對傳入的數(shù)組執(zhí)行任何安全檢查叠蝇,如果array參數(shù)是一個空數(shù)組年缎,如上定義的minMax(:)在試圖訪問array[0]時會觸發(fā)一個運行時錯誤单芜。

為了安全地處理這個“空數(shù)組”問題缓溅,將minMax(_:)函數(shù)改寫為使用可選元組返回類型,并且當(dāng)數(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(_:)函數(shù)返回的是一個實際的元組值還是nil:

if let bounds = minMax([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ù)名稱(Function Parameter Names)
函數(shù)參數(shù)都有一個外部參數(shù)名(external parameter name)和一個局部參數(shù)名(local parameter name)淤齐。外部參數(shù)名用于在函數(shù)調(diào)用時標注傳遞給函數(shù)的參數(shù)更啄,局部參數(shù)名在函數(shù)的實現(xiàn)內(nèi)部使用居灯。

func someFunction(firstParameterName: Int, secondParameterName: Int) {
    // function body goes here
    // firstParameterName and secondParameterName refer to
    // the argument values for the first and second parameters
}
someFunction(1, secondParameterName: 2)

一般情況下怪嫌,第一個參數(shù)省略其外部參數(shù)名岩灭,第二個以及隨后的參數(shù)使用其局部參數(shù)名作為外部參數(shù)名。所有參數(shù)必須有獨一無二的局部參數(shù)名柱恤。盡管多個參數(shù)可以有相同的外部參數(shù)名,但不同的外部參數(shù)名能讓你的代碼更有可讀性泡孩。

指定外部參數(shù)名(Specifying External Parameter Names)

你可以在局部參數(shù)名前指定外部參數(shù)名仑鸥,中間以空格分隔:

func someFunction(externalParameterName localParameterName: Int) {
    // function body goes here, and can use localParameterName
    // to refer to the argument value for that parameter
}

注意
如果你提供了外部參數(shù)名矗漾,那么函數(shù)在被調(diào)用時敞贡,必須使用外部參數(shù)名。
這個版本的sayHello(_:)函數(shù)获列,接收兩個人的名字击孩,會同時返回對他倆的問候:

func sayHello(to person: String, and anotherPerson: String) -> String {
    return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello(to: "Bill", and: "Ted"))
// prints "Hello Bill and Ted!"

為每個參數(shù)指定外部參數(shù)名后鹏漆,在你調(diào)用sayHello(to:and:)函數(shù)時兩個外部參數(shù)名都必須寫出來艺玲。

使用外部函數(shù)名可以使函數(shù)以一種更富有表達性的類似句子的方式調(diào)用饭聚,并使函數(shù)體意圖清晰,更具可讀性法绵。

忽略外部參數(shù)名(Omitting External Parameter Names)

如果你不想為第二個及后續(xù)的參數(shù)設(shè)置外部參數(shù)名酪碘,用一個下劃線(_)代替一個明確的參數(shù)名兴垦。

func someFunction(firstParameterName: Int, _ secondParameterName: Int) {
    // function body goes here
    // firstParameterName and secondParameterName refer to
    // the argument values for the first and second parameters
}
someFunction(1, 2)

注意
因為第一個參數(shù)默認忽略其外部參數(shù)名稱,顯式地寫下劃線是多余的犀忱。

默認參數(shù)值(Default Parameter Values)

你可以在函數(shù)體中為每個參數(shù)定義默認值(Deafult Values)阴汇。當(dāng)默認值被定義后搀庶,調(diào)用這個函數(shù)時可以忽略這個參數(shù)铜异。

func someFunction(parameterWithDefault: Int = 12) {
    // function body goes here
    // if no arguments are passed to the function call,
    // value of parameterWithDefault is 12
}
someFunction(6) // parameterWithDefault is 6
someFunction() // parameterWithDefault is 12

注意
將帶有默認值的參數(shù)放在函數(shù)參數(shù)列表的最后揍庄。這樣可以保證在函數(shù)調(diào)用時,非默認參數(shù)的順序是一致的沃测,同時使得相同的函數(shù)在不同情況下調(diào)用時顯得更為清晰蒂破。

可變參數(shù)(Variadic Parameters)

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

可變參數(shù)的傳入值在函數(shù)體中變?yōu)榇祟愋偷囊粋€數(shù)組攀甚。例如秋度,一個叫做 numbers 的 Double... 型可變參數(shù)钱床,在函數(shù)體內(nèi)可以當(dāng)做一個叫 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)
// 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ù)滥壕。
如果函數(shù)有一個或多個帶默認值的參數(shù)兽泣,而且還有一個可變參數(shù)唠倦,那么把可變參數(shù)放在參數(shù)表的最后稠鼻。

輸入輸出參數(shù)(In-Out Parameters)

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

定義一個輸入輸出參數(shù)時芋簿,在參數(shù)定義前加 inout 關(guān)鍵字与斤。一個輸入輸出參數(shù)有傳入函數(shù)的值荚恶,這個值被函數(shù)修改谒撼,然后被傳出函數(shù),替換原來的值抵皱。想獲取更多的關(guān)于輸入輸出參數(shù)的細節(jié)和相關(guān)的編譯器優(yōu)化呻畸,請查看輸入輸出參數(shù)一節(jié)伤为。

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

注意
輸入輸出參數(shù)不能有默認值肋演,而且可變參數(shù)不能用 inout 標記。
下面是例子蜕乡,swapTwoInts(a: b:) 函數(shù)层玲,有兩個分別叫做 a 和 b 的輸入輸出參數(shù):

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

這個 swapTwoInts(a: b:) 函數(shù)簡單地交換 a 與 b 的值反症。該函數(shù)先將 a 的值存到一個臨時常量 temporaryA 中惰帽,然后將 b 的值賦給 a该酗,最后將 temporaryA 賦值給 b士嚎。

你可以用兩個 Int 型的變量來調(diào)用 swapTwoInts(a: b:) 莱衩。需要注意的是笨蚁,someInt 和 anotherInt 在傳入 swapTwoInts(a: b:) 函數(shù)前趟庄,都加了 & 的前綴:

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(a: b:) 函數(shù)中被修改猫十,盡管它們的定義在函數(shù)體外拖云。

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

函數(shù)類型(Function Types)
每個函數(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 和 multiplyTwoInts鸣哀。這兩個函數(shù)都接受兩個 Int 值我衬, 返回一個Int值饰恕。

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

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

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

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

使用函數(shù)類型(Using Function Types)

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

var mathFunction: (Int, Int) -> Int = addTwoInts
這個可以解讀為:

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

addTwoInts 和 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ù)給常量或變量時,你可以讓 Swift 來推斷其函數(shù)類型:

let anotherMathFunction = addTwoInts
// anotherMathFunction is inferred to be of type (Int, Int) -> Int

函數(shù)類型作為參數(shù)類型(Function Types as Parameter Types)

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

下面是另一個例子,正如上面的函數(shù)一樣获搏,同樣是輸出某種數(shù)學(xué)運算結(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ù)叫 mathFunction,類型是(Int, Int) -> Int常熙,你可以傳入任何這種類型的函數(shù)纬乍;第二個和第三個參數(shù)叫 a 和 b,它們的類型都是 Int裸卫,這兩個值作為已給出的函數(shù)的輸入值仿贬。

當(dāng) printMathResult(::_:) 被調(diào)用時,它被傳入 addTwoInts 函數(shù)和整數(shù)3和5墓贿。它用傳入3和5調(diào)用 addTwoInts茧泪,并輸出結(jié)果:8蜓氨。

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

函數(shù)類型作為返回類型(Function Types as Return Types)

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

下面的這個例子中定義了兩個簡單函數(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
}

下面這個叫做 chooseStepFunction(:) 的函數(shù)宜猜,它的返回類型是 (Int) -> Int 類型的函數(shù)泼返。chooseStepFunction(:) 根據(jù)布爾值 backwards 來返回 stepForward(:) 函數(shù)或 stepBackward(:) 函數(shù):

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    return backwards ? stepBackward : stepForward
}

你現(xiàn)在可以用 chooseStepFunction(_:) 來獲得兩個函數(shù)其中的一個:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function

上面這個例子中計算出從 currentValue 逐漸接近到0是需要向正數(shù)走還是向負數(shù)走。currentValue 的初始值是3姨拥,這意味著 currentValue > 0 是真的(true)绅喉,這將使得 chooseStepFunction(:) 返回 stepBackward(:) 函數(shù)。一個指向返回的函數(shù)的引用保存在了 moveNearerToZero 常量中叫乌。

現(xiàn)在柴罐,moveNearerToZero 指向了正確的函數(shù),它可以被用來數(shù)到0:

print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!

嵌套函數(shù)(Nested Functions)
這章中你所見到的所有函數(shù)都叫全局函數(shù)(global functions)憨奸,它們定義在全局域中革屠。你也可以把函數(shù)定義在別的函數(shù)體中,稱作嵌套函數(shù)(nested functions)排宰。

默認情況下似芝,嵌套函數(shù)是對外界不可見的,但是可以被它們的外圍函數(shù)(enclosing function)調(diào)用板甘。一個外圍函數(shù)也可以返回它的某一個嵌套函數(shù)党瓮,使得這個函數(shù)可以在其他域中被使用。

你可以用返回嵌套函數(shù)的方式重寫 chooseStepFunction(_:) 函數(shù):

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backwards ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(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)容合作請聯(lián)系作者
  • 序言:七十年代末盐类,一起剝皮案震驚了整個濱河市麻诀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌傲醉,老刑警劉巖蝇闭,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異硬毕,居然都是意外死亡呻引,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門吐咳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逻悠,“玉大人元践,你說我怎么就攤上這事⊥耍” “怎么了单旁?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長饥伊。 經(jīng)常有香客問我象浑,道長,這世上最難降的妖魔是什么琅豆? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任愉豺,我火速辦了婚禮,結(jié)果婚禮上茫因,老公的妹妹穿的比我還像新娘蚪拦。我一直安慰自己,他們只是感情好冻押,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布驰贷。 她就那樣靜靜地躺著,像睡著了一般洛巢。 火紅的嫁衣襯著肌膚如雪饱苟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天狼渊,我揣著相機與錄音,去河邊找鬼类垦。 笑死狈邑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚤认。 我是一名探鬼主播米苹,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼砰琢!你這毒婦竟也來了蘸嘶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤陪汽,失蹤者是張志新(化名)和其女友劉穎训唱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挚冤,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡况增,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了训挡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澳骤。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡歧强,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出为肮,到底是詐尸還是另有隱情摊册,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布颊艳,位于F島的核電站茅特,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏籽暇。R本人自食惡果不足惜温治,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望戒悠。 院中可真熱鬧熬荆,春花似錦、人聲如沸绸狐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寒矿。三九已至突琳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間符相,已是汗流浹背拆融。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留啊终,地道東北人镜豹。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像蓝牲,于是被迫代替她去往敵國和親趟脂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

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