函數(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)