第八章 函數(shù)

函數(shù)

函數(shù)是執(zhí)行特定任務(wù)的自包含代碼塊官撼。給定函數(shù)一個(gè)名稱作為標(biāo)識(shí)策彤,并在需要的時(shí)候通過(guò)調(diào)用其名稱來(lái)執(zhí)行任務(wù)靴庆。

Swift 的統(tǒng)一函數(shù)語(yǔ)法十分靈活褪贵,可以表示簡(jiǎn)單的無(wú)參數(shù)的 C 風(fēng)格函數(shù)掂之,也可以表示有本地參數(shù)及外部參數(shù)的復(fù)雜 Objective-C 風(fēng)格函數(shù)。參數(shù)可以為簡(jiǎn)單的函數(shù)調(diào)用提供默認(rèn)值脆丁,也可以作為輸入/輸出參數(shù)進(jìn)行傳遞板惑,并在函數(shù)執(zhí)行完成的時(shí)候改變參數(shù)值。

Swift 中每個(gè)函數(shù)都有一種類型偎快,由函數(shù)的參數(shù)類型及返回值類型組成冯乘。并且可以像使用 Swift 中的其他類型那樣來(lái)使用函數(shù)類型,因此將函數(shù)作為參數(shù)傳遞給其他函數(shù)晒夹,或者將函數(shù)作為函數(shù)返回值就變得很容易裆馒。函數(shù)可以定義在其他函數(shù)作用域中,用以封裝一段有用功能丐怯。

8.1 定義和調(diào)用函數(shù)

當(dāng)定義一個(gè)函數(shù)時(shí)喷好,你可以任意定義一個(gè)或多個(gè)給定命名及類型的值作為輸入(稱為形參),同時(shí)可以給定一個(gè)當(dāng)函數(shù)執(zhí)行結(jié)束后的返回值類型(稱為返回類型)读跷。

每個(gè)函數(shù)都有一個(gè)函數(shù)名梗搅,用來(lái)描述函數(shù)所執(zhí)行的任務(wù)。當(dāng)要使用一個(gè)函數(shù)時(shí)效览,你可以調(diào)用其名稱并且傳遞與參數(shù)類型相符的值无切。一個(gè)函數(shù)的實(shí)參必須與形參順序一致。

例如下面例子中的函數(shù) sayHello 丐枉,它以一個(gè)人名作為輸入?yún)?shù)哆键,返回對(duì)這個(gè)人的一句問(wèn)候語(yǔ)。為了實(shí)現(xiàn)這個(gè)功能瘦锹,需要定義一個(gè)名為 personName 的字符串輸入?yún)?shù)籍嘹,以及一個(gè)包含了對(duì)這個(gè)人名的問(wèn)候語(yǔ)的字符串返回值類型:

<此處添加代碼2.6.1 - 1>

所有這些信息匯集到一個(gè)以 func 關(guān)鍵字作為前綴的函數(shù)的定義中。使用符號(hào) -> 來(lái)指明返回值類型(一個(gè)連字符后面跟一個(gè)右箭頭)弯院,后面跟返回類型名稱辱士。

函數(shù)的定義描述了函數(shù)的功能,它期望接收什么听绳,以及當(dāng)它執(zhí)行結(jié)束時(shí)會(huì)返回什么颂碘。函數(shù)的定義使其可以清晰并且無(wú)歧義地在你的代碼中被調(diào)用:

<此處添加代碼2.6.1 - 2>

你可以通過(guò)在圓括號(hào)內(nèi)傳遞一個(gè)字符串變量來(lái)調(diào)用 sayHello 函數(shù),例如 sayHello(“Anna”)辫红。由于該函數(shù)返回一個(gè)字符串值凭涂,sayHello 可以被包含在 println 函數(shù)中來(lái)打印其返回值,如上所示贴妻。

sayHello 函數(shù)主體首先定義了一個(gè)名為 greeting 的字符串常量切油,并且將其設(shè)置為對(duì) personName 的一句問(wèn)候語(yǔ)。之后使用關(guān)鍵字 return 來(lái)將?greeting 作為函數(shù)返回值名惩。當(dāng) return greeting 語(yǔ)句被調(diào)用的時(shí)候澎胡,函數(shù)的執(zhí)行結(jié)束并且返回當(dāng)前 greeting 的值。

你可以傳入不同的值來(lái)調(diào)用 sayHello 函數(shù)娩鹉。上面的例子展示了當(dāng)傳入值為 “Anna” 以及 “Brian” 時(shí)函數(shù)的行為攻谁。對(duì)于不同的情況函數(shù)返回相對(duì)應(yīng)的問(wèn)候語(yǔ)。

為了簡(jiǎn)化函數(shù)主體弯予,可以將消息創(chuàng)建和返回合并到一條語(yǔ)句中:

<此處添加代碼2.6.1 - 3>

8.2 函數(shù)的形參和返回值

在 Swift 中戚宦,函數(shù)的形參和返回值具有很高的靈活性。你可以定義任何事情锈嫩,無(wú)論是僅具有一個(gè)形參的簡(jiǎn)單工具函數(shù)受楼,還是具有豐富形參和不同形參選項(xiàng)的復(fù)雜函數(shù)。

多輸入形參

如下函數(shù)接收一個(gè)半開(kāi)區(qū)間的開(kāi)始和結(jié)束位置呼寸,然后計(jì)算在此區(qū)間內(nèi)有多少個(gè)元素:

<此處添加代碼2.6.2 - 1>

無(wú)形參函數(shù)

函數(shù)并為要求要定義輸入形參艳汽。如下是一個(gè)無(wú)形參函數(shù),任何時(shí)候調(diào)用都返回相同的字符串消息:

<此處添加代碼2.6.2 - 2>

函數(shù)定義時(shí)仍需要在函數(shù)名后面跟一對(duì)圓括號(hào)对雪,即使它不帶有任何參數(shù)河狐。當(dāng)函數(shù)被調(diào)用是,函數(shù)名后面同樣需要跟一對(duì)圓括號(hào)瑟捣。

無(wú)返回值的函數(shù)

函數(shù)并未要求要定義返回類型馋艺。如下是一個(gè)無(wú)返回值版本的 sayHello 函數(shù),我們稱它為 sayGoodbye迈套,它只會(huì)打印自己的字符串值而不是返回它:

<此處添加代碼2.6.2 - 3>

因?yàn)樗⒉环祷厝魏沃嫡筛疲瘮?shù)定義也不需要包含返回剪頭(->)及返回類型。

注意:

嚴(yán)格來(lái)說(shuō)交汤,即使沒(méi)有定義任何返回值雏赦,函數(shù) sayGoodbye 仍然返回了一個(gè)值。沒(méi)有定義返回類型的函數(shù)返回一個(gè)特殊類型的值 Void芙扎。這是一個(gè)空的元組星岗,沒(méi)有包含任何元素,可以被寫(xiě)作 ()戒洼。

當(dāng)一個(gè)函數(shù)被調(diào)用時(shí)俏橘,它的返回類型可以被忽略:

<此處添加代碼2.6.2 - 4>

第一個(gè)函數(shù) printAndCount,打印一個(gè)字符串圈浇,并以 Int 類型返回其字符數(shù)寥掐。第二個(gè)函數(shù) printWithoutCounting靴寂,調(diào)用第一個(gè)函數(shù),但忽略其返回值召耘。當(dāng)?shù)诙€(gè)函數(shù)被調(diào)用時(shí)百炬,消息仍由第一個(gè)函數(shù)打印,但并未使用它的返回值污它。

注意:

返回值可以被忽略剖踊,但一個(gè)定義了返回值的函數(shù)必須有返回值。一個(gè)定義了返回類型的函數(shù)衫贬,不允許在控制流結(jié)束不返回值德澈,這樣會(huì)導(dǎo)致編譯錯(cuò)誤。

多返回值的函數(shù)

你可以使用一個(gè)元組作為函數(shù)的返回類型固惯,來(lái)返回一個(gè)由多個(gè)返回值組成的復(fù)合返回值梆造。

下面的例子定義了一個(gè)名為minMax的函數(shù),用來(lái)查找到int類型數(shù)組中的最小值和最大值:

<此處添加代碼2.6.2 - 5>

minMax 函數(shù)返回包含兩個(gè) int 類型值的一個(gè)元組葬毫。這兩個(gè)值的標(biāo)簽為 min 和 max澳窑,當(dāng)解包函數(shù)返回值的時(shí)候可以利用名字分別訪問(wèn)到它們。

minMax 函數(shù)主體首先將兩個(gè)工作變量 currentMin 和 currentMax 設(shè)置為數(shù)組中的第一個(gè)數(shù)供常。然后函數(shù)遍歷數(shù)組中剩余的所有值以查看是否有比 currentMin 小或比 currentMax 大的值摊聋。最后,所有值中的最大值最小值組成元組返回栈暇。

元組的成員值已經(jīng)作為函數(shù)返回類型的一部分麻裁,因此可以使用點(diǎn)語(yǔ)法訪問(wèn)到最小值和最大值:

<此處添加代碼2.6.2 - 6>

需要注意的是元組的成員不需要被命名,因?yàn)樵M是由函數(shù)返回的源祈,他們的名字已經(jīng)被指定為函數(shù)返回類型的一部分煎源。

可選元組返回類型

如果函數(shù)返回的元組類型可能出現(xiàn)整個(gè)元組為空值的情況,你可以使用一個(gè)可選元組返回類型來(lái)表征整個(gè)元組可能為 nil香缺。在元組類型的圓括號(hào)后面添加一個(gè)問(wèn)號(hào)可以表示可選元組返回類型手销,例如 (Int, Int)? 或 (String, Int, Bool)?。

注意:

一個(gè)可選元組類型例如 (Int, Int)? 和一個(gè)包含可選類型的元組例如 (Int?, Int?) 是不同的图张。 可選元組類型的整個(gè)元組是可選的锋拖,并不只是元組中單獨(dú)的值可選。

上面 minMax 函數(shù)返回一個(gè)包含兩個(gè) Int 值的元組祸轮。但是兽埃,函數(shù)并不會(huì)對(duì)傳入的數(shù)組進(jìn)行任何安全檢查。如果數(shù)組參數(shù)中包含有空數(shù)組 — 元素?cái)?shù)為零的數(shù)組 — 上面定義的 minMax 函數(shù)將會(huì)在訪問(wèn)一個(gè)元素為空的數(shù)組時(shí)觸發(fā)運(yùn)行時(shí)錯(cuò)誤适袜。

要安全處理 “空數(shù)組” 的場(chǎng)景柄错,可以將 minMax 函數(shù)寫(xiě)成返回可選元組,并在數(shù)組為空的時(shí)候返回nil:

<此處添加代碼2.6.2 - 7>

你可以使用可選元祖來(lái)檢查此版本的 minMax 函數(shù)是否返回一個(gè)真正的元組或者是返回nil:?

<此處添加代碼2.6.2 - 8>

函數(shù)可以有多個(gè)輸入?yún)?shù),寫(xiě)到函數(shù)的括號(hào)內(nèi)售貌,以逗號(hào)隔開(kāi)给猾。

如下函數(shù)接收一個(gè)半開(kāi)區(qū)間的開(kāi)始和結(jié)束位置,然后計(jì)算在此區(qū)間內(nèi)有多少個(gè)元素:

<此處添加代碼2.6.2 - 9>


8.3 函數(shù)形參名

上面的所有函數(shù)都為其形參定義了行參名:

<此處添加代碼2.6.3 - 1>

但是颂跨,這些參數(shù)的名稱僅能在函數(shù)本身主體內(nèi)部使用敢伸,不能在調(diào)用函數(shù)時(shí)使用。這些形參名被稱為本地形參名毫捣,因?yàn)樗麄儍H能在函數(shù)主體內(nèi)部使用。

外部形參名?

有時(shí)帝际,當(dāng)你調(diào)用一個(gè)函數(shù)的時(shí)候蔓同,將每一個(gè)形參進(jìn)行命名是非常有用的,這樣可以清晰地表明每一個(gè)傳入?yún)?shù)的含義和目的蹲诀。

如果希望調(diào)用你的函數(shù)的用戶提供形參名斑粱,除了定義形參名,還需要為每個(gè)參數(shù)定義外部參數(shù)名脯爪。外部形參名書(shū)寫(xiě)在本地形參名之前则北,用一個(gè)空格隔開(kāi):

<此處添加代碼2.6.3 - 2>

注意:

如果你為一個(gè)參數(shù)提供外部形參名,外部形參名必須在調(diào)用時(shí)使用痕慢。

舉一個(gè)例子尚揣,考慮下面這個(gè)函數(shù),在兩個(gè)字符串中間插入第三個(gè)字符串 “joiner” 來(lái)連接它們:

<此處添加代碼2.6.3 - 3>

當(dāng)你調(diào)用這個(gè)函數(shù)的時(shí)候掖举,你傳入的三個(gè)參數(shù)目的并不是非常明確:

<此處添加代碼2.6.3 - 4>

為了讓這些參數(shù)值的目的更清晰快骗,為每一個(gè)join函數(shù)的參數(shù)定義一個(gè)外部形參名:

<此處添加代碼2.6.3 - 5>

這個(gè)版本的 join 函數(shù),第一個(gè)形參的外部名稱是 string塔次,內(nèi)部名稱是 s1方篮;第二個(gè)參數(shù)的外部名稱是 tostring,內(nèi)部名稱是 s2励负;第三個(gè)參數(shù)的外部名稱是 withJoiner藕溅,內(nèi)部名稱是 joiner。

現(xiàn)在你可以使用這些外部形參名來(lái)明確的調(diào)用這個(gè)函數(shù):

<此處添加代碼2.6.3 - 6>

使用了外部形參名的 join 函數(shù)继榆,能更形象巾表、更像語(yǔ)句一樣被用戶調(diào)用,同時(shí)還使得函數(shù)主體可讀性更強(qiáng)略吨、意圖更明確攒发。

注意:

當(dāng)別人第一次閱讀你的代碼可能不知道函數(shù)參數(shù)的含義時(shí),就需要考慮使用外部形參名了晋南。如果每個(gè)形參的目的清晰的話惠猿,就不需要指定外部形參名了。

外部形參名簡(jiǎn)寫(xiě)

如果你想為一個(gè)函數(shù)形參提供外部形參名,而本地形參名已經(jīng)使用了一個(gè)合適的名稱偶妖,那你就不需要為這個(gè)參數(shù)書(shū)寫(xiě)兩次形參名姜凄。只需要書(shū)寫(xiě)一次形參名,并用一個(gè) “#” 符號(hào)作為前綴趾访。著能告訴 Swift 使用這個(gè)名稱同時(shí)作為本地形參名和外部形參名态秧。

下面的例子定義了一個(gè)名為 containsCharacter 的函數(shù),通過(guò)在本地形參名前添加 # 符號(hào)來(lái)定義外部形參名:

<此處添加代碼2.6.3 - 7>

這個(gè)函數(shù)對(duì)于形參名的選擇使得函數(shù)主體更加清晰易讀扼鞋,并且在函數(shù)調(diào)用是不會(huì)有歧義:

<此處添加代碼2.6.3 - 8>

默認(rèn)形參值

你可以為每一個(gè)形參定義一個(gè)默認(rèn)值作為函數(shù)定義的一部分申鱼。如果定義了默認(rèn)值,那么在調(diào)用時(shí)就可以省略該形參云头。

注意:

將帶默認(rèn)值的形參寫(xiě)在函數(shù)參數(shù)列表的末尾捐友。這能確保函數(shù)的所有調(diào)用都使用相同的無(wú)默認(rèn)值形參順序,并且在每種情況下都清晰的調(diào)用函數(shù)溃槐。

如下是一個(gè)先前的 join 函數(shù)匣砖,它為形參 joiner 提供了默認(rèn)值:

<此處添加代碼2.6.3 - 9>

如果 join 函數(shù)被調(diào)用時(shí)為 joiner 提供了字符串值,那么字符串值將用于連接兩個(gè)字符串昏滴,跟之前一樣:

<此處添加代碼2.6.3 - 10>

但如果函數(shù)被調(diào)用時(shí)沒(méi)有為 joiner 提供任何值猴鲫,就會(huì)使用默認(rèn)值空格符 “ ”:

<此處添加代碼2.6.3 - 11>

帶默認(rèn)值的外部形參

在大多數(shù)情況下,為所有形參提供一個(gè)帶默認(rèn)值的外部名稱是很有用谣殊。這樣可以確保在函數(shù)被調(diào)用時(shí)形參提供的值所對(duì)應(yīng)的實(shí)參有明確的目的拂共。

為了讓這個(gè)過(guò)程更簡(jiǎn)單,Swift 可為每個(gè)定義的形參提供一個(gè)自動(dòng)外部名稱姻几。這個(gè)自動(dòng)外部名和本地形參名是相同的匣缘,就如同在本地形參名前面添加 # 號(hào)一樣。

如下是一個(gè)先前的 join 函數(shù)鲜棠,沒(méi)有為任何形參提供外部名稱肌厨,但仍為 joiner 形參提供了默認(rèn)值:

<此處添加代碼2.6.3 - 12>

在這個(gè)例子中,Swift 自動(dòng)為帶默認(rèn)值的形參 joiner 提供了外部名稱豁陆。在函數(shù)被調(diào)用的時(shí)候外部名稱必須提供柑爸,這使得函數(shù)的調(diào)用清晰無(wú)歧義:

<此處添加代碼2.6.3 - 13>

可變形參

一個(gè)可變形參可以接受零個(gè)或多個(gè)指定類型的值。當(dāng)函數(shù)被調(diào)用時(shí)盒音,可變形參可以用來(lái)指定傳入?yún)?shù)數(shù)量不固定表鳍。在參數(shù)類型名后面寫(xiě)三個(gè)句號(hào) (…) 。

傳遞給可變形參的值在函數(shù)體內(nèi)部以符合的類型存儲(chǔ)在數(shù)組中祥诽。例如一個(gè)名為 numbers 類型為 double 的可變形參譬圣,在函數(shù)體就成為一個(gè)名為 numbers 類型為 double[] 的常量數(shù)組。

下面的例子可以計(jì)算任意長(zhǎng)度數(shù)字?jǐn)?shù)組的平均數(shù):

<此處添加代碼2.6.3 - 14>

注意:函數(shù)最多只能有一個(gè)可變形參雄坪,并且它必須出現(xiàn)在參數(shù)表的最后厘熟,以避免多個(gè)參數(shù)引發(fā)歧義。如果你的函數(shù)中有一個(gè)或多個(gè)帶有默認(rèn)值的參數(shù),則將可變形參放在參數(shù)列表的最后面绳姨。

常量形參和變量形參

函數(shù)的形參默認(rèn)是常量登澜。試圖在函數(shù)體內(nèi)修改形參的值將引發(fā)編譯錯(cuò)誤。這確保了你不會(huì)誤修改一個(gè)形參的值飘庄。

但是脑蠕,有時(shí)函數(shù)的形參的變量副本是非常有用的。這樣可以避免你自己為一個(gè)或多個(gè)參數(shù)申明變量跪削。變量參數(shù)是變量而非常量谴仙,它能提供給函數(shù)一個(gè)可以修改的值拷貝。

在形參名前面添加 var 關(guān)鍵字來(lái)申明變量參數(shù):

<此處添加代碼2.6.3 - 15>

這個(gè)例子定義了一個(gè)新的方法稱為 alignRight碾盐,將出入的字符串與另一個(gè)更長(zhǎng)的字符串進(jìn)行右對(duì)齊晃跺。左側(cè)的空白使用指定的占位符來(lái)填充。在這里例子中廓旬,字符串 “Hello” 被轉(zhuǎn)換為字符串 “——Hello”哼审。

函數(shù) alignRight 函數(shù)將輸入?yún)?shù) string 定義為變量參數(shù)谐腰。這意味著 string 可以作為本地變量來(lái)使用孕豹,初始化為傳入字符串值, 并且可以在函數(shù)體內(nèi)被修改十气。

函數(shù)首先計(jì)算出需要在左邊添加幾個(gè)字符励背,以使得整個(gè)字符串右對(duì)齊。這個(gè)值存儲(chǔ)在本地的常量 amountToPad 中砸西。如果不需要填充字符(即當(dāng) amountToPad 小于1)時(shí)叶眉,函數(shù)直接將輸入值 string 返回。

否則芹枷,函數(shù)在現(xiàn)有字符串左邊填充 amountToPad 個(gè) pad 字符并返回衅疙。在字符串值修改的時(shí)候其一直使用 string 變量類型。

注意:

對(duì)變量參數(shù)的修改效果不會(huì)超過(guò)函數(shù)調(diào)用范圍鸳慈,并且在函數(shù)體外部不可見(jiàn)饱溢。變量參數(shù)僅存在于函數(shù)調(diào)用生命周期內(nèi)。

In-Out 形參

如上所述走芋,變量形參僅能在函數(shù)內(nèi)部被修改绩郎。如果你想讓一個(gè)函數(shù)改變形參值,并且讓修改效果延續(xù)到函數(shù)調(diào)用結(jié)束之后翁逞,那么可以將參數(shù)定義為 in-out 形參肋杖。

在形參定義前添加 in-out 關(guān)鍵字來(lái)定義一個(gè) in-out 形參。In-Out 形參有一個(gè)傳遞進(jìn)函數(shù)的值挖函,在函數(shù)中被修改状植,并傳回出函數(shù)以替換原來(lái)的值。

你只能傳遞一個(gè)變量作為 in-out 形參對(duì)應(yīng)的實(shí)參。不能傳遞常量或者字面量作為實(shí)參浅萧,因?yàn)槌A亢妥置媪坎荒鼙恍薷闹鹕场.?dāng)你傳遞一個(gè)變量作為 in-out 形參的實(shí)參時(shí),需要在變量前面直接加上 & 符號(hào)以指示函數(shù)可以修改其值洼畅。

注意:

in-out 參數(shù)不能有默認(rèn)值吩案,并且可變形參不能被標(biāo)記為 in-out 形參。如果你標(biāo)記一個(gè)形參為in-out帝簇,就不能將其標(biāo)記為 var 或著 let徘郭。

如下是一個(gè)示例函數(shù)稱為 swapTwoInts,其有兩個(gè) in-out 整形形參 a 和 b:

<此處添加代碼2.6.3 - 16>

swapTwoInts 函數(shù)只是簡(jiǎn)單地交換 a丧肴,b 的值残揉。它將 a 的值儲(chǔ)存在一個(gè)稱為 temporaryA 的臨時(shí)常量中,將 b 的值賦給 a芋浮,然后將 temporaryA 的值賦給 b抱环。

你可以使用兩個(gè) Int 型變量調(diào)用 swapTwoInts 函數(shù)來(lái)交換他們的值。需要注意的是纸巷,當(dāng)他們被傳遞給 swapTwoInts 函數(shù)時(shí)镇草,someInt 和 anotherInt 名稱前面需要添加 & 符號(hào):

<此處添加代碼2.6.3 - 17>

上面的例子展示了 someInt 和 anotherInt 的原始值被 swapTwoInts 函數(shù)改變,即使他們定義在函數(shù)的外部瘤旨。


8.4 函數(shù)類型

每一個(gè)函數(shù)都有一個(gè)特定的函數(shù)類型梯啤,由參數(shù)類型和返回值類型組成。

例如:

<此處添加代碼2.6.4 - 1>

這個(gè)例子中定義了兩個(gè)簡(jiǎn)單的數(shù)學(xué)函數(shù) addTwoInts 和 multiplyTwoInts存哲。每個(gè)函數(shù)都接受兩個(gè) Int 值因宇,并返回一個(gè) Int 值,執(zhí)行適當(dāng)?shù)臄?shù)學(xué)運(yùn)算并返回結(jié)果祟偷。

這兩個(gè)函數(shù)的類型都是 (Int, Int) -> Int察滑。可以這樣理解:

“ 這是一個(gè)擁有兩個(gè) Int 型參數(shù)修肠,且返回一個(gè) Int 型值的函數(shù)類型贺辰。”

下面是另一個(gè)例子氛赐,該函數(shù)沒(méi)有參數(shù)和返回值:

<此處添加代碼2.6.4 - 2>

這個(gè)函數(shù)的類型是 () -> () 魂爪,即 “一個(gè)沒(méi)有形參的函數(shù),并且返回 Void”艰管。沒(méi)有指明返回類型的函數(shù)會(huì)返回 Void滓侍,在 Swift 中相當(dāng)于一個(gè)空元組,寫(xiě)為 ()牲芋。

使用函數(shù)類型

你可以像使用 Swift 中的其他類型一樣使用函數(shù)類型撩笆。例如捺球,你可以定義一個(gè)常量或變量作為函數(shù)類型,并為變量指定一個(gè)函數(shù):

<此處添加代碼2.6.4 - 3>

這可以解讀為:

“ 定義一個(gè)名為 mathFunction 的變量夕冲,該變量的類型是為 ‘一個(gè)接受兩個(gè) Int 型參數(shù)氮兵,返回一個(gè) Int 值的函數(shù)’,設(shè)置這個(gè)新的變量為 addTwoInts 函數(shù)歹鱼∑唬”

addTwoInts 函數(shù)和 mathFunction 具有相同的類型,因此 Swift 在賦值時(shí)進(jìn)行類型檢查弥姻。

現(xiàn)在你可以使用 mathFunction 來(lái)調(diào)用指定的函數(shù):

<此處添加代碼2.6.4 - 4>

具有匹配的相同類型的函數(shù)可以被賦值給同一個(gè)變量南片,就跟非函數(shù)類型一樣:

<此處添加代碼2.6.4 - 5>

如同其他類型一樣,當(dāng)你把函數(shù)賦值給一個(gè)常量或者變量時(shí)庭敦,你可以讓 Swift 自行去判斷其類型:

<此處添加代碼2.6.4 - 6>

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

你可以使用形如 (Int, Int) -> Int 的函數(shù)類型疼进,來(lái)作為另一個(gè)函數(shù)的形參。這使得當(dāng)函數(shù)被調(diào)用時(shí)秧廉,保留了一些功能交給調(diào)用函數(shù)去實(shí)現(xiàn)伞广。

如下的例子打印出了上面數(shù)學(xué)函數(shù)的結(jié)果:

<此處添加代碼2.6.4 - 7>

這個(gè)例子定義了一個(gè)有三個(gè)形參名為 printMathResult 的函數(shù)。第一個(gè)形參稱為 mathFunction疼电,類型是 (Int, Int) -> Int嚼锄。你可以傳遞任何此類型的函數(shù)作為第一個(gè)形參的實(shí)參。第二和第三個(gè)形參成為 a 和 b澜沟,都是 Int 類型灾票。用作數(shù)學(xué)函數(shù)的兩個(gè)輸入值峡谊。

當(dāng) printMathResult 被調(diào)用時(shí)茫虽,傳遞進(jìn)了 addTwoInt 函數(shù),整數(shù) 3 和 5既们。然后函數(shù)用 3 和 5 調(diào)用了傳入的函數(shù)濒析,打印出結(jié)果 8。

printMathResult 函數(shù)的功能是打印出傳入的特定類型數(shù)學(xué)函數(shù)的結(jié)果啥纸。它不關(guān)心傳入函數(shù)的實(shí)現(xiàn)号杏,只關(guān)心傳入函數(shù)的類型是否正確。這使得 printMathResult 函數(shù)能以類型的安全(type-safe)的方式將部分功能轉(zhuǎn)交給調(diào)用者斯棒。

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

你可以將一個(gè)函數(shù)類型作為另一個(gè)函數(shù)的返回類型盾致。可以在返回函數(shù)的返回剪頭 (->) 后面添加完整的函數(shù)類型來(lái)實(shí)現(xiàn)荣暮。

下面的例子定義了兩個(gè)簡(jiǎn)單的函數(shù)稱為 stepForward 和 stepBackward庭惜。stepForward 函數(shù)返回輸入值加一的結(jié)果,stepBackword 返回輸入值減一的結(jié)果穗酥。這兩個(gè)函數(shù)的類型都是 (Int) -> Int:

<此處添加代碼2.6.4 - 8>

這個(gè)名為 chooseStepFunction 的函數(shù)护赊,它返回一個(gè)類型為 (Int) -> Int 的函數(shù)惠遏,其根據(jù)布爾類型傳入?yún)?shù) backwards 的值來(lái)決定返回 stepForward 還是 stepBackward:

<此處添加代碼2.6.4 - 9>

現(xiàn)在你可以使用 chooseStepFunction 來(lái)獲取一個(gè)遞增或者遞減函數(shù):

<此處添加代碼2.6.4 - 10>

上面的例子可以計(jì)算出是否需要通過(guò)遞增或者遞減來(lái)讓 currentValue 變量趨于 0. currentValue 的初始值是3,因此當(dāng) currentValue > 0 時(shí)返回真骏啰,這使 chooseStepFunction 返回 stepBackward 函數(shù)节吮。返回函數(shù)的引用存儲(chǔ)在名為 moveNearerToZero 的常量中。

從而 moveNearerToZero 可以執(zhí)行正確的功能判耕,可以用來(lái)計(jì)數(shù)到 0:

<此處添加代碼2.6.4 - 11>


8.5 嵌套函數(shù)

前面所有章節(jié)中所涉及的函數(shù)都是全局函數(shù)透绩,定義在全局作用域中。你也可以在函數(shù)體中定義函數(shù)壁熄,被稱為嵌套函數(shù)渺贤。

嵌套函數(shù)默認(rèn)對(duì)外界不可見(jiàn),但仍可以通過(guò)其包裹函數(shù)(enclosing Function)調(diào)用它请毛。 包裹函數(shù)可以通過(guò)返回一個(gè)嵌套函數(shù)使得這個(gè)嵌套函數(shù)可以被外部使用志鞍。

重寫(xiě)上面的 chooseStepFunction 例子以返回嵌套函數(shù):

<此處添加代碼2.6.5- 1>


Tips:

1. 函數(shù)參數(shù)名稱的省略:

Objective-C 的函數(shù)在命名上用幾乎完整的英文表述了函數(shù)名和詳細(xì)的參數(shù)名,這使得函數(shù)的可讀性極其優(yōu)秀方仿,如:UIBarButton的工廠方法:- initWithImage: style:? target: action:固棚。Swift中也延續(xù)了這個(gè)優(yōu)點(diǎn),并且提供了“_” 和 “#” 符號(hào)來(lái)要求調(diào)用時(shí)添加或者不添加參數(shù)名稱仙蚜,為了達(dá)到和Objective-C完全一致的風(fēng)格此洲,可以在第一個(gè)參數(shù)前添加“_”符號(hào)。

2.可變參數(shù)函數(shù)的推薦寫(xiě)法:

Swift 和 Objective-C 中都限制最多只能有一組可變參數(shù)委粉,可變參數(shù)必須只能作為方法中最后一個(gè)參數(shù)來(lái)使用呜师,并且可變參數(shù)都必須是同一個(gè)類型。當(dāng)需要處理多種類型的場(chǎng)景下贾节,可以使用 Any 作為參數(shù)類型汁汗,這類似于 Objective-C 中的 id 類型。處理可變參數(shù)時(shí)推薦使用“_”符號(hào)栗涂,是可變參數(shù)看起來(lái)是一個(gè)匿名的參數(shù)列表知牌,風(fēng)格就和 Objective-C 統(tǒng)一。

3. 函數(shù)的參數(shù)修飾符需要注意的問(wèn)題:

函數(shù)的參數(shù)默認(rèn)是用 let 修飾的斤程,也就是說(shuō)函數(shù)內(nèi)不可改變參數(shù)的值角寸。在函數(shù)內(nèi)改變值會(huì)產(chǎn)生編譯錯(cuò)誤,如:

func functionName(variable: Int) -> Int {

return variable *= 2;

}

如需要改變參數(shù)值忿墅,需要顯示指定參數(shù)修飾符為 var:

func functionName(var variable: Int) -> Int {

return variable *= 2;

}

并且需要注意的是扁藕,參數(shù)的修飾是具有傳遞限制的,參數(shù)在傳遞調(diào)用的場(chǎng)景下必須保持七參數(shù)疚脐。

4. Swift 1.2變化部分及與 Objective-C 的關(guān)聯(lián):

Swift 1.2版本發(fā)布同時(shí)為 Objective-C API 中可以表示參數(shù)亿柑,返回值,屬性亮曹,變量等等的“nullability”屬性橄杨。這個(gè)nullability標(biāo)示符影響了Objective-C API在Swift的可選類型值秘症。

![1423711358267173.jpg](http://upload-images.jianshu.io/upload_images/63265-e883bdddaf970d5a.jpg)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市式矫,隨后出現(xiàn)的幾起案子乡摹,更是在濱河造成了極大的恐慌,老刑警劉巖采转,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聪廉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡故慈,警方通過(guò)查閱死者的電腦和手機(jī)板熊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)察绷,“玉大人干签,你說(shuō)我怎么就攤上這事〔鸷常” “怎么了容劳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)闸度。 經(jīng)常有香客問(wèn)我竭贩,道長(zhǎng),這世上最難降的妖魔是什么莺禁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任留量,我火速辦了婚禮,結(jié)果婚禮上哟冬,老公的妹妹穿的比我還像新娘楼熄。我一直安慰自己,他們只是感情好柒傻,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布孝赫。 她就那樣靜靜地躺著较木,像睡著了一般红符。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伐债,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天预侯,我揣著相機(jī)與錄音,去河邊找鬼峰锁。 笑死萎馅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的虹蒋。 我是一名探鬼主播糜芳,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼飒货,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了峭竣?” 一聲冷哼從身側(cè)響起塘辅,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎皆撩,沒(méi)想到半個(gè)月后扣墩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扛吞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年呻惕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滥比。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亚脆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盲泛,到底是詐尸還是另有隱情型酥,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布查乒,位于F島的核電站弥喉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏玛迄。R本人自食惡果不足惜由境,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蓖议。 院中可真熱鬧虏杰,春花似錦、人聲如沸勒虾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)修然。三九已至笛钝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間愕宋,已是汗流浹背玻靡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留中贝,地道東北人囤捻。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像邻寿,于是被迫代替她去往敵國(guó)和親蝎土。 傳聞我的和親對(duì)象是個(gè)殘疾皇子视哑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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