Swift - 閉包


閉包(Closures)是自包含的功能代碼塊聊倔,可以在代碼中使用或者用來作為參數(shù)傳值。
Swift中的閉包與C語言和OC只能中的block以及其他一些編程語言中的匿名函數(shù)是比較相似的见妒。
全局函數(shù)和嵌套函數(shù)其實(shí)就是特殊的閉包须揣。

閉包的形式有:

1.全局函數(shù)
有名字但是不能捕獲任何值钱豁。
2.嵌套函數(shù)
有名字牲尺,也能捕獲封閉函數(shù)內(nèi)的值。
3.閉包表達(dá)式
無名閉包溃卡,使用輕量級(jí)語法塑煎,可以根據(jù)上下文環(huán)境捕獲值最铁。

Swift中的閉包有很多相對(duì)優(yōu)化的地方:

1.根據(jù)上下文推斷參數(shù)和返回值類型。
2.從單行表達(dá)式閉包中隱式返回漱挎。(也就是閉包體只有一行代碼磕谅,可以省略return)
3.可以使用簡(jiǎn)書參數(shù)名雾棺,如$0捌浩,$1。(從0開始进统,表示第i個(gè)參數(shù)...)
4.提供了尾隨閉包語法螟碎。

語法

以下定義了一個(gè)接收參數(shù)并返回指定類型的閉包語法:

{(parameters) -> return type in
    statements
}

實(shí)例

let ex = {print("Swift 閉包函數(shù)掉分。")}
ex()

以上程序的執(zhí)行輸出結(jié)果為:

Swift 閉包實(shí)例

以下閉包形式接收兩個(gè)參數(shù)并返回布爾值:

{(Int, Int) -> Bool in
    Statement 1
    ......
    Statement n
}

實(shí)例

let divide = {(value1: Int, val2: Int) -> Int in
    return val1 / val2
}

let result = divide(200, 20)
print(result)

以上程序的執(zhí)行結(jié)果為:

10

閉包表達(dá)式

閉包表達(dá)式是一種利用簡(jiǎn)潔語法構(gòu)建內(nèi)聯(lián)閉包的方式叉抡。閉包表達(dá)式提供了一些語法優(yōu)化答毫,使得撰寫閉包變得簡(jiǎn)單明了洗搂。

sorted方法

Swift標(biāo)準(zhǔn)庫提供了名為sorted(by:)的方法耘拇,會(huì)根據(jù)您提供的用于排列的閉包函數(shù)將已知類型數(shù)組中的值進(jìn)行排序惫叛。
排序完成后嘉涌,sorted(by:)方法會(huì)返回一個(gè)與原數(shù)組大小相同,包含同類型元素且元素已正確排序的新數(shù)組扔役,原數(shù)組不會(huì)被sorted(by:)方法修改警医。
sorted(by:)方法需要傳入兩個(gè)參數(shù):
1.已知類型的數(shù)組
2.閉包函數(shù)预皇,該閉包函數(shù)需要傳入與數(shù)組元素類型相同的兩個(gè)值,并返回一個(gè)布爾類型值來表明當(dāng)排序結(jié)束后傳入的第一個(gè)參數(shù)排在第二個(gè)參數(shù)前面還是后面拗馒。如果第一個(gè)參數(shù)值出現(xiàn)在第二個(gè)參數(shù)值前面诱桂,排序閉包函數(shù)需要返回true呈昔,反之返回false。
實(shí)例

let names = ["AT", "AE", "D", "S", "BE"]

//使用普通函數(shù)或內(nèi)嵌函數(shù)提供排序功能
//閉包函數(shù)類型需為(String肝劲, String) -> Bool
func backwords(s1: String, s2: String) -> Bool {
    return s1 -> s2
}
var reversed = name.sorted(by: backwords)
print(reversed)

以上程序的執(zhí)行結(jié)果為:

["S", "D", "BE", "AT", "AE"]

如果第一個(gè)字符串(s1)大于第二個(gè)字符串(s2)辞槐,backwords函數(shù)返回true粘室,表示在新的數(shù)組中s1應(yīng)該出現(xiàn)在s2前衔统。對(duì)于字符串中的字符來說,“大于”表示:按照字母順序較晚出現(xiàn)舱殿。這意味著字母“B”大于字母“A”沪袭,字符串“S”大于字符串“D”樟氢。其將進(jìn)行字母逆序排序,“AT”將會(huì)排在“AE”之前焚碌。

參數(shù)名稱縮寫

Swift自動(dòng)為內(nèi)聯(lián)函數(shù)提供了參數(shù)名稱縮寫功能十电,你可以直接通過$0,$1台盯,$2來順序調(diào)用閉包的參數(shù)静盅。
實(shí)例

let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted( by : {$0 > $1} )
print( reversed )

$0和$1表示閉包中第一個(gè)和第二個(gè)String類型的參數(shù)蒿叠。
以上程序的執(zhí)行結(jié)果為:

["S", "D", "BE", "AT", "AE"]

如果你在閉包表達(dá)式中使用參數(shù)名稱縮寫,你可以在閉包參數(shù)列表中省略對(duì)其定義市咽,并且對(duì)應(yīng)參數(shù)名稱縮寫的類型會(huì)通過函數(shù)類型進(jìn)行推斷施绎。in關(guān)鍵字同樣也可以被省略谷醉。

運(yùn)算符函數(shù)

實(shí)際上還有一中更簡(jiǎn)短的方式來撰寫上面例子中的閉包表達(dá)式冈闭。
Swift的String類型定義了關(guān)于大于號(hào)(>)的字符串實(shí)現(xiàn)拒秘,其作為一個(gè)函數(shù)接收兩個(gè)String類型的參數(shù)并返回Bool的參值躺酒。而這正好與sort(_:)方法的第二個(gè)參數(shù)需要的函數(shù)類型相符合羹应。因此,您可以簡(jiǎn)單地傳遞一個(gè)大于號(hào)园匹,Swift可以自動(dòng)推斷出您想使用大于號(hào)的字符串函數(shù)實(shí)現(xiàn):

let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: >)
print(reversed)

以上程序執(zhí)行輸出結(jié)果為:

["S", "D", "BE", "AT", "AE"]

尾隨閉包

尾隨閉包是一個(gè)書寫在函數(shù)括號(hào)之后的閉包表達(dá)式裸违,函數(shù)支持將其作為最后一個(gè)參數(shù)調(diào)用。

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函數(shù)體部分
}

// 以下是不使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure({
    // 閉包主體部分
})

// 以下是使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure() {
  // 閉包主體部分
}

實(shí)例

let names = ["AT", "AE", "D", "S", "BE"]

//尾隨閉包
var reversed = names.sorted() { $0 > $1 }
print(reversed)

sort() 后的 { $0 > $1} 為尾隨閉包枪汪。
以上程序執(zhí)行輸出結(jié)果為:

["S", "D", "BE", "AT", "AE"]

注意:如果函數(shù)只需要閉包表達(dá)式一個(gè)參數(shù)雀久,當(dāng)您使用尾隨閉包時(shí)赖捌,您甚至可以把()省略掉。

reversed = names.sorted { $0 > $1 }

捕獲值

閉包可以在其定義的上下文中捕獲常量或者變量越庇。
即使定義這些常量和變量的原域已經(jīng)不存在悦荒,閉包仍然可以在閉包函數(shù)體內(nèi)引用和修改這些值搬味。
Swift最簡(jiǎn)單的閉包形式是嵌套函數(shù)碰纬,也就是定義在其他函數(shù)的函數(shù)體內(nèi)的函數(shù)问芬。
嵌套函數(shù)可以捕獲其外部函數(shù)所有的參數(shù)以及定義的常量和變量。
看這個(gè)例子:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

一個(gè)函數(shù)makeIncrementor强戴,它有一個(gè)Int型的參數(shù)amout骑歹,并且它有一個(gè)外部參數(shù)名字forIncrement道媚,意味著你調(diào)用的時(shí)候最域,必須使用這個(gè)外部名字镀脂。返回值是一個(gè)() -> Int的函數(shù)。
函數(shù)體內(nèi)钞馁,聲明了變量runningTotal和一個(gè)函數(shù)incrementor僧凰。
incrementor函數(shù)并沒有獲取任何參數(shù)训措,但是在函數(shù)體內(nèi)訪問runningTotal和amount變量绩鸣。這是因?yàn)槠渫ㄟ^補(bǔ)貨在包含它的函數(shù)體內(nèi)已經(jīng)存在的runningTotal和amount變量而實(shí)現(xiàn)呀闻。
由于沒有修改amount變量潜慎,incrementor實(shí)際上捕獲并存儲(chǔ)了該變量的一個(gè)副本铐炫,而該副本隨著incrementor一同被存儲(chǔ)。
所以我們調(diào)用這個(gè)函數(shù)時(shí)會(huì)累加:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
       return runningTotal
    }
    return incrementor

}

let incrementByTen = makeIncrementor(forIncrement: 10)

// 返回的值為10
print(incrementByTen())

// 返回的值為20
print(incrementByTen())

// 返回的值為30
print(incrementByTen())

以上程序的執(zhí)行結(jié)果為:

10
20
30

閉包是引用類型

上面的例子只能怪科贬,incrementByTen是常量榜掌,但是這些常量指向的閉包仍然可以增加其捕獲的變量值憎账。這是因?yàn)楹瘮?shù)和閉包都是引用類型鼠哥。
無論你將函數(shù)看政、閉包賦值給一個(gè)常量還是變量,你實(shí)際上都是將常量允蚣、變量的值設(shè)置為對(duì)應(yīng)函數(shù)嚷兔、閉包的引用。上面的實(shí)例中同衣,incrementByTen指向閉包的引用是一個(gè)常量,而并非閉包內(nèi)容本身埠况。
這也意味著如果您將閉包賦值給兩個(gè)不同常量棵癣、變量辕翰,兩個(gè)值都會(huì)指向同一個(gè)閉包:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)

// 返回的值為10
incrementByTen()

// 返回的值為20
incrementByTen()

// 返回的值為30
incrementByTen()

// 返回的值為40
incrementByTen()

let alsoIncrementByTen = incrementByTen

// 返回的值也為50
print(alsoIncrementByTen())

以上程序的執(zhí)行結(jié)果為:

50

下一篇:“Swift - 枚舉、結(jié)構(gòu)體”

http://www.reibang.com/p/30f8d904ba04

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狈谊,一起剝皮案震驚了整個(gè)濱河市喜命,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌河劝,老刑警劉巖渊抄,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異丧裁,居然都是意外死亡护桦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門煎娇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人催享,你說我怎么就攤上這事。” “怎么了蜗细?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)白粉。 經(jīng)常有香客問我系冗,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闽晦。我一直安慰自己唧垦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布褒搔。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪念逞。 梳的紋絲不亂的頭發(fā)上符匾,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天痴晦,我揣著相機(jī)與錄音碧浊,去河邊找鬼驹止。 笑死衣洁,一個(gè)胖子當(dāng)著我的面吹牛环凿,可吹牛的內(nèi)容都是我干的屎慢。 我是一名探鬼主播环肘,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼益涧,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼扭弧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起痰滋,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤拨匆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后峻汉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體聂喇,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡誊辉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蛙紫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了僵驰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秒赤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情睦刃,我是刑警寧澤砚嘴,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站涩拙,受9級(jí)特大地震影響际长,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吃环,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一也颤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧郁轻,春花似錦、人聲如沸文留。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽燥翅。三九已至骑篙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間森书,已是汗流浹背靶端。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凛膏,地道東北人杨名。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像猖毫,于是被迫代替她去往敵國和親台谍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • 閉包是自包含的函數(shù)代碼塊吁断,可以在代碼中被傳遞和使用趁蕊。Swift 中的閉包與 C 和 Objective-C 中的代...
    窮人家的孩紙閱讀 1,708評(píng)論 1 5
  • 閉包是功能性自包含模塊坞生,可以在代碼中被傳遞和使用。Swift中的閉包與 C 和 Objective-C中的 blo...
    AirZilong閱讀 349評(píng)論 0 2
  • 閉包可以從定義它們的上下文中捕獲和存儲(chǔ)對(duì)任何常量和變量的引用掷伙。 這被稱為關(guān)閉這些常量和變量是己。 Swift處理所有的...
    Joker_King閱讀 593評(píng)論 0 2
  • Swift 中的閉包是自包含的函數(shù)代碼塊,可以在代碼中被傳遞和使用任柜。類似于OC中的Block以及其他函數(shù)的匿名函數(shù)...
    喬克_叔叔閱讀 522評(píng)論 1 3
  • * 閉包 是自包含的函數(shù)代碼塊赃泡,可以在代碼中被傳遞和使用。swift中的閉包和Objective-C中的代碼塊(b...
    EndEvent閱讀 856評(píng)論 4 8