窺探 Swift 之 函數(shù)與閉包的應(yīng)用實(shí)例

一.Swift中的函數(shù)

1.函數(shù)的定義與使用

在介紹Swift中的函數(shù)之前,我想用Objective-C中的一個(gè)簡(jiǎn)單的加法函數(shù)來(lái)作為引子大猛,然后類比著實(shí)現(xiàn)一下Swift中相同功能的函數(shù)历涝。關(guān)于函數(shù)定義就比較簡(jiǎn)單了诅需,就是一些語(yǔ)法的東西,下面的代碼片段是Objc中求兩個(gè)整數(shù)之和的函數(shù)荧库,并返回兩個(gè)數(shù)的和堰塌。

- (NSInteger)sumNumber1:(NSInteger) number1
                number2:(NSInteger) number2 {    return number1 + number2;
}

函數(shù)的功能比較簡(jiǎn)單了,就是把兩個(gè)整數(shù)傳進(jìn)來(lái)分衫,然后返回兩個(gè)整數(shù)的和场刑。接下來(lái)將用Swift語(yǔ)言實(shí)現(xiàn),也好通過(guò)這個(gè)實(shí)例來(lái)熟悉一下Swift語(yǔ)言中定義函數(shù)的語(yǔ)法蚪战。下方是Swift語(yǔ)言中求兩個(gè)整數(shù)之和的函數(shù)牵现。語(yǔ)法比較簡(jiǎn)單了,在Swift中定義函數(shù)邀桑,我們會(huì)使用到關(guān)鍵字func來(lái)聲明函數(shù)瞎疼。

//函數(shù)定義
 func sum (number1:Int, number2:Int) -> Int{
     return number1 + number2;
 }

用文字來(lái)描述Swift定義基本函數(shù)的語(yǔ)法就是: func 函數(shù)名 (形參列表) -> 返回值類型 { 函數(shù)體},這樣你就可以定義一個(gè)函數(shù)了壁畸。當(dāng)然贼急,函數(shù)定義時(shí)還有好多其他的用法茅茂,下面會(huì)詳細(xì)介紹。上面函數(shù)的調(diào)用方法如下:

let sumTwoNubmer = sum(2, number2: 3);

2.函數(shù)中的形參列表

(1) 默認(rèn)的形參是常量(let)

在函數(shù)的形參列表中太抓,默認(rèn)的形參是常量空闲。也就是相當(dāng)于用let關(guān)鍵字對(duì)形參進(jìn)行修飾了。我們可以做個(gè)試驗(yàn)走敌,把上面加法函數(shù)做一個(gè)修改碴倾,在加法函數(shù)中對(duì)number1進(jìn)行加1操作,你會(huì)得到一個(gè)錯(cuò)誤掉丽,這個(gè)錯(cuò)誤的大體意思就是“number1是不可被修改的跌榔,因?yàn)樗莑et類型的常量”。并且編譯器還給人出了Fix-it(修復(fù))的方案机打,就是在number1前面使用var關(guān)鍵字進(jìn)行修飾矫户,使其成為變量,這樣才可以修改其值残邀。

上面說(shuō)這么多皆辽,一句話:形參默認(rèn)是常量,如果你想讓其是變量芥挣,那么你可以使用var關(guān)鍵字進(jìn)行修飾驱闷,這樣被關(guān)鍵字var修飾的變量在函數(shù)中就可以被修改。下方就是報(bào)的這個(gè)錯(cuò)誤空免,和編譯器提供的解決方案空另。(在Objc中默認(rèn)可以在函數(shù)中改變形參的值)

img
(2)給形參命名

為了代碼的可讀性和可維護(hù)性,我們?cè)诙x函數(shù)時(shí)蹋砚,需要為每個(gè)參數(shù)名一個(gè)名字扼菠,這樣調(diào)用者見名知意,很容易就知道這個(gè)參數(shù)代表什么意思了坝咐。接下來(lái)還是在上述加法函數(shù)中進(jìn)行修改循榆,為每個(gè)參數(shù)名一個(gè)名字,并看一下調(diào)用方式墨坚。修改上面的函數(shù)秧饮,給第一個(gè)形參命名成numberOne, 第二個(gè)形參為numberTwo, 下方是修改后的函數(shù)。 緊接著sum()函數(shù)的調(diào)用方式也會(huì)有所改變泽篮,在調(diào)用函數(shù)時(shí)編譯器會(huì)給出參數(shù)的名稱盗尸,這樣調(diào)用者一目了然。

//函數(shù)定義
func sum (numberOne number1:Int, numberTwo number2:Int) -> Int{
    return number1 + number2;
}
 
let sumTwoNubmer = sum(numberOne: 10, numberTwo: 20);

調(diào)用上述函數(shù)時(shí)帽撑,下方是編譯器給出的提示泼各,一目了然呢。

img

關(guān)于Swift中參數(shù)名的內(nèi)容亏拉,要說(shuō)明的是在Swift1.0的時(shí)候扣蜻,你可以在參數(shù)前面添加上#號(hào)寸癌,然后參數(shù)名就與變量(或者常量)的名字相同,而Swift2.0后這個(gè)東西去掉了弱贼,因?yàn)槟J(rèn)就相當(dāng)于Swift1.0中添加#號(hào)。

(3) 函數(shù)的傳參與傳引用

先暫且這么說(shuō)著磷蛹,在C語(yǔ)言的函數(shù)中可以給函數(shù)傳入?yún)?shù)吮旅,或者傳入實(shí)參的內(nèi)存地址就是所謂的傳引用。如果傳入的是引用的話味咳,在函數(shù)中對(duì)值進(jìn)行修改的話庇勃,那么出了函數(shù),這個(gè)被修改的值是可以被保留的槽驶。在Swift中也是可以的责嚷,不過(guò)你需要使用inout關(guān)鍵字修飾形參,并且在使用該函數(shù)時(shí)掂铐,用&來(lái)修飾罕拂。這一點(diǎn)和C語(yǔ)言中類似,&就是取地址符全陨。下方是inout使用的一個(gè)小實(shí)例爆班。

 func incrementStepTwo (inout myNumber:Int) {
     myNumber += 2
 }
 var myTestNumber = 6
 incrementStepTow(&myTestNumber)  //myTestNumber = 8

myTestNumber變量經(jīng)過(guò)incrementStepTwo()函數(shù)后,其值就會(huì)增加2辱姨。當(dāng)然前提是myTestNumber是變量柿菩,如果myTestNumber是常量的話,那么對(duì)不起雨涛,調(diào)用該函數(shù)就會(huì)報(bào)錯(cuò)枢舶,下面是把var改成let后IDE給的錯(cuò)誤提示。錯(cuò)誤原因很顯然是你動(dòng)了一個(gè)不該動(dòng)的值替久,也就是常量不可再次被修改的凉泄。

img
(4) 不定參數(shù)函數(shù)

不定參數(shù)函數(shù)也就是形參的個(gè)數(shù)是不定的,但是形參的類型必須是相同的侣肄。不定形參在使用時(shí)怎么取呢旧困?不定個(gè)數(shù)的形參實(shí)際上是一個(gè)數(shù)組,我們可以通過(guò)for循環(huán)的形式來(lái)遍歷出每個(gè)形參的值稼锅,然后使用就可以了吼具。下方incrementMultableAdd()函數(shù)的形參的個(gè)數(shù)是不定的,其功能是求多個(gè)整數(shù)的和矩距。在函數(shù)中我們只需遍歷每個(gè)參數(shù)拗盒,然后把每個(gè)參數(shù)進(jìn)行相加,最后返回所求的和即可锥债。函數(shù)比較簡(jiǎn)單陡蝇,再此就不在啰嗦了痊臭。

img
(5) 默認(rèn)形參值

在Swift語(yǔ)言中是支持給形參賦初始值的,這一點(diǎn)在其他一些編程語(yǔ)言中也是支持的登夫。但是Objective-C這么看似古老的語(yǔ)言中就不支持給形參指定初始值广匙,在Swift這門現(xiàn)代編程語(yǔ)言中是支持這一特性的。默認(rèn)參數(shù)要從參數(shù)列表后開始為參數(shù)指定默認(rèn)值恼策,不然就會(huì)報(bào)錯(cuò)鸦致。下方就是為函數(shù)的形參指定默認(rèn)參數(shù)的示例。一個(gè)表白的方法sayLove(), 形參youName默認(rèn)是“山伯”涣楷, 形參loverName默認(rèn)是“英臺(tái)”分唾。 緊接著是sayLove函數(shù)的三種不同的調(diào)用方式,在調(diào)用函數(shù)時(shí)你可以不傳參數(shù)狮斗,可以傳一個(gè)參數(shù)绽乔,當(dāng)然傳兩個(gè)也是沒(méi)問(wèn)題的。

img

因?yàn)楹瘮?shù)的每個(gè)參數(shù)都是有名字的碳褒,在含有默認(rèn)參數(shù)的函數(shù)調(diào)用時(shí)折砸,可以給任意一個(gè)參數(shù)進(jìn)行傳值,其他參數(shù)取默認(rèn)值沙峻,這也是Swift的一大特色之一鞍爱,具體請(qǐng)看如下簡(jiǎn)單的代碼示例:

img

3.函數(shù)類型

每個(gè)函數(shù)都有自己的所屬類型,函數(shù)類型說(shuō)白了就是如果兩個(gè)函數(shù)參數(shù)列表相同以及返回值類型相同专酗,那么這兩個(gè)函數(shù)就有著相同的函數(shù)類型睹逃。在Swift中可以定義一個(gè)變量或者常量來(lái)存儲(chǔ)一個(gè)函數(shù)的類型。接下來(lái)將用過(guò)一個(gè)實(shí)例還介紹一下函數(shù)類型是個(gè)什么東西祷肯。

(1) 首先創(chuàng)建兩個(gè)函數(shù)類型相同的函數(shù)沉填,一個(gè)函數(shù)返回兩個(gè)整數(shù)的差值,另一個(gè)函數(shù)返回兩個(gè)整數(shù)的乘積佑笋。當(dāng)然這兩個(gè)函數(shù)比較簡(jiǎn)單翼闹,直接上代碼:

//現(xiàn)定義兩個(gè)函數(shù)類型相同的函數(shù)
func diff (number1:Int, number2:Int) -> Int {
    return number1 - number2;
}
 
func mul (number1:Int, number2:Int) -> Int {
    return number1 * number2;
}

(2) 函數(shù)定義好后,接著要定義個(gè)一個(gè)枚舉來(lái)枚舉每種函數(shù)的類型蒋纬,下面定義這個(gè)枚舉在選擇函數(shù)時(shí)會(huì)用到猎荠,枚舉定義如下:

//定義兩種計(jì)算的枚舉類型
 enum CountType:Int {
     case DiffCount = 0
     case MulCount
 }

(3) 接下來(lái)就是把(1)和(2)中定義的東西通過(guò)一個(gè)函數(shù)來(lái)組合起來(lái)。說(shuō)白了蜀备,就是定義個(gè)函數(shù)來(lái)通過(guò)枚舉值返回這個(gè)枚舉值所對(duì)應(yīng)的函數(shù)類型关摇。有時(shí)候說(shuō)多了容易犯迷糊,就直接上代碼得了碾阁。下方函數(shù)的功能就是根據(jù)傳進(jìn)來(lái)的枚舉值來(lái)返回相應(yīng)的函數(shù)類型输虱。

//選擇類型的函數(shù),并返回相應(yīng)的函數(shù)類型
func choiseCountType(countType:CountType) -> ((Int, Int) -> Int) {
    //函數(shù)類型變量
    var myFuncType:(Int, Int) -> Int
     
    switch countType {
    case .DiffCount:
        myFuncType = diff
    case .MulCount:
        myFuncType = mul
    }
    return myFuncType;
}

(4) 接下來(lái)就是使用(3)中定義的函數(shù)了脂凶,首先我們需要定義一個(gè)相應(yīng)函數(shù)類型((Int, Int) -> Int)的變量來(lái)接收choiseCountType()函數(shù)中返回的函數(shù)類型宪睹,然后調(diào)用該函數(shù)類型變量愁茁,在Playground中執(zhí)行的結(jié)果如下:

img

4.函數(shù)嵌套

我們可以把 3 中的代碼使用函數(shù)嵌套進(jìn)行重寫,在Swift中是支持函數(shù)嵌套的亭病。 所以可以吧3.1和3.2中的函數(shù)放到3.3函數(shù)中的鹅很,所以我們可以對(duì)上述代碼使用函數(shù)嵌套進(jìn)行重寫。使用函數(shù)嵌套重寫后的代碼如下所示罪帖,當(dāng)然道宅,choiseCountType()函數(shù)的調(diào)用方式?jīng)]用發(fā)生改變,重寫后的調(diào)用方式和3.4中的調(diào)用方式是一樣一樣的胸蛛。

//選擇類型的函數(shù),并返回相應(yīng)的函數(shù)類型
func choiseCountType(countType:CountType) -> ((Int, Int) -> Int) {
     
    //現(xiàn)定義兩個(gè)函數(shù)類型相同的函數(shù)
    func diff (number1:Int, number2:Int) -> Int {
        return number1 - number2;
    }
     
    func mul (number1:Int, number2:Int) -> Int {
        return number1 * number2;
    }
 
     
    //函數(shù)類型變量
    var myFuncType:(Int, Int) -> Int
     
    switch countType {
    case .DiffCount:
        myFuncType = diff
    case .MulCount:
        myFuncType = mul
    }
    return myFuncType;
}

二. 閉包

說(shuō)道Swift中的閉包呢樱报,不得不提的就是Objective-C中的Block, 其實(shí)兩者是一個(gè)東西葬项,使用方式以及使用場(chǎng)景都是相同的。我們完全可以類比著Objective-C中的Block來(lái)介紹一下Swift中的Closure(閉包)迹蛤。其實(shí)就是匿名函數(shù)民珍。接下來(lái)的這段內(nèi)容,先介紹一下Swift中Closure的基本語(yǔ)法盗飒,然后在類比著ObjC中的Block窺探一下Closure的使用場(chǎng)景嚷量。

1.Closure變量的聲明

Closure就是匿名函數(shù),我們可以定義一個(gè)閉包變量逆趣,而這個(gè)閉包變量的類型就是我們上面介紹的“函數(shù)類型”蝶溶。定義一個(gè)閉包變量其實(shí)就是定義一個(gè)特定函數(shù)類型的變量,方式如下宣渗。因?yàn)镃losure變量沒(méi)有賦初始值抖所,所以我們把其聲明為可選類型的變量。在使用時(shí)痕囱,用!強(qiáng)制打開即可田轧。

var myCloure0:((Int, Int) -> Int)?

除了上面的方式外,我們還用另一種常用的聲明閉包變量的方式鞍恢。那就是使用關(guān)鍵字typealias定義一個(gè)特定函數(shù)類型傻粘,我們就可以拿著這個(gè)類型去聲明一個(gè)Closure變量了,如下所示

//定義閉包類型 (就是一個(gè)函數(shù)類型)
 typealias MyClosureType = (Int, Int) -> Int
 var myCloure:MyClosureType?

2.給Closure變量賦值

給Closure變量賦值帮掉,其實(shí)就是把一個(gè)函數(shù)體賦值給一個(gè)函數(shù)類型的變量弦悉,和函數(shù)的定義區(qū)別不大。但是給閉包變量賦值的函數(shù)體中含有參數(shù)列表蟆炊,并且參數(shù)列表和真正的函數(shù)體之間使用關(guān)鍵字in來(lái)分割警绩。 閉包可選變量的調(diào)用方式與普通函數(shù)沒(méi)什么兩樣,唯一不同的是這個(gè)函數(shù)需要用!來(lái)強(qiáng)制打開才可以使用盅称。賦值和調(diào)用方式如下肩祥。

img

3.數(shù)組中常用的閉包函數(shù)

在Swift的數(shù)組中自帶了一些比較好用的閉包函數(shù)后室,例如Map, Filter, Reduce。接下來(lái)就好好的看一下這些閉包混狠,用起來(lái)還是比較爽的岸霹。

(1) Map(映射)

說(shuō)到Map的用法和功能,不能不說(shuō)的是如果你使用過(guò)ReactiveCocoa框架将饺,那么對(duì)里邊的Sequence中的Map的使用方式并不陌生贡避。其實(shí)兩者的使用方法和功能是極為相似的。如果你沒(méi)使用過(guò)RAC中的Map予弧,那也無(wú)關(guān)緊要刮吧,接下來(lái)我們先上段代碼開看一下數(shù)組中的Map閉包函數(shù)。

img

通過(guò)上面的代碼段以及運(yùn)行結(jié)果掖蛤,我們不難看出杀捻,map閉包函數(shù)的功能就是對(duì)數(shù)組中的每一項(xiàng)進(jìn)行遍歷,然后通過(guò)映射規(guī)則對(duì)數(shù)組中的每一項(xiàng)進(jìn)行處理蚓庭,最終的返回結(jié)果是處理后的數(shù)組(以一個(gè)新的數(shù)組形式出現(xiàn))致讥。當(dāng)然,原來(lái)數(shù)組中的元素值是保持不變的器赞,這就是map閉包函數(shù)的用法與功能垢袱。

(2) Filter (過(guò)濾器)

Filter的用法還是比較好理解的,F(xiàn)ilter就是一個(gè)漏勺港柜,就是用來(lái)過(guò)濾符合條件的數(shù)據(jù)的请契。在ReactiveCocoa中的Sequence也是有Filter的,用法還是來(lái)過(guò)濾Sequence中的數(shù)據(jù)的夏醉。而在數(shù)組中的Filter用來(lái)過(guò)濾數(shù)組中的數(shù)據(jù)姚糊,并且返回新的數(shù)組,新的數(shù)組中存放的就是符合條件的數(shù)據(jù)授舟。Filter的用法如下實(shí)例救恨,下方的實(shí)例就是一個(gè)身高的過(guò)濾,過(guò)濾掉身高小于173的人释树,返回大于等于173的身高數(shù)據(jù)肠槽。

img
(3)Reduce

在ReactiveCocoa中也是有Reduce這個(gè)概念的,ReactiveCocoa中使用Reduce來(lái)合并消減信號(hào)量奢啥。在swift的數(shù)組中使用Reduce閉包函數(shù)來(lái)合并items, 并且合并后的Value秸仙。下方的實(shí)例是一個(gè)Salary的數(shù)組,其中存放的是每個(gè)月的薪水桩盲。我們要使用Reduce閉包函數(shù)來(lái)計(jì)算總的薪水寂纪。下方是DEMO的截圖:

img
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捞蛋,更是在濱河造成了極大的恐慌孝冒,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拟杉,死亡現(xiàn)場(chǎng)離奇詭異庄涡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)搬设,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門穴店,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人拿穴,你說(shuō)我怎么就攤上這事适秩“栏啵” “怎么了建钥?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵糕篇,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我该窗,道長(zhǎng),這世上最難降的妖魔是什么蚤霞? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任酗失,我火速辦了婚禮,結(jié)果婚禮上昧绣,老公的妹妹穿的比我還像新娘规肴。我一直安慰自己,他們只是感情好夜畴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布拖刃。 她就那樣靜靜地躺著,像睡著了一般贪绘。 火紅的嫁衣襯著肌膚如雪兑牡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天税灌,我揣著相機(jī)與錄音均函,去河邊找鬼。 笑死菱涤,一個(gè)胖子當(dāng)著我的面吹牛苞也,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播粘秆,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼如迟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起殷勘,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤此再,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后劳吠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體引润,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年痒玩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淳附。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蠢古,死狀恐怖奴曙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情草讶,我是刑警寧澤洽糟,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站堕战,受9級(jí)特大地震影響坤溃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嘱丢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一薪介、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧越驻,春花似錦汁政、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至并巍,卻和暖如春目木,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背懊渡。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工嘶窄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人距贷。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓柄冲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親忠蝗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子现横,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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