日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Swift5.1 语言指南(九) 闭包

發(fā)布時間:2023/11/30 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Swift5.1 语言指南(九) 闭包 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
?微信公眾號:山青詠芝(shanqingyongzhi)
?博客園地址:山青詠芝(https://www.cnblogs.com/strengthen/)
?GitHub地址:https://github.com/strengthen/LeetCode
?原文地址:https://www.cnblogs.com/strengthen/p/9728063.html?
?如果鏈接不是山青詠芝的博客園地址,則可能是爬取作者的文章。
?原文已修改更新!強(qiáng)烈建議點(diǎn)擊原文地址閱讀!支持作者!支持原創(chuàng)!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

閉包是自包含的功能塊,可以在代碼中傳遞和使用。Swift中的閉包類似于C和Objective-C中的塊以及其他編程語言中的lambdas。

閉包可以從定義它們的上下文中捕獲和存儲對任何常量和變量的引用。這被稱為關(guān)閉那些常量和變量。Swift為您處理捕獲的所有內(nèi)存管理。

注意

如果您不熟悉捕獲的概念,請不要擔(dān)心。下面在捕獲值中詳細(xì)解釋了它。

全球和嵌套函數(shù),如推出的功能,實(shí)際上是封閉的特殊情況。閉包采用以下三種形式之一:

  • 全局函數(shù)是具有名稱但不捕獲任何值的閉包。
  • 嵌套函數(shù)是具有名稱的閉包,可以從其封閉函數(shù)中捕獲值。
  • Closure表達(dá)式是一種未命名的閉包,用輕量級語法編寫,可以從周圍的上下文中捕獲值。

Swift的閉包表達(dá)式具有干凈,清晰的風(fēng)格,優(yōu)化可以在常見場景中鼓勵簡潔,無雜亂的語法。這些優(yōu)化包括:

  • 從上下文中推斷參數(shù)和返回值類型
  • 單表達(dá)式閉包的隱式返回
  • 速記參數(shù)名稱
  • 尾隨閉包語法

關(guān)閉表達(dá)式

嵌套函數(shù)(在嵌套函數(shù)中引入)是一種方便的方法,可以將自包含的代碼塊命名和定義為更大函數(shù)的一部分。但是,在沒有完整聲明和名稱的情況下編寫類似函數(shù)的構(gòu)造的更短版本有時是有用的。當(dāng)您使用將函數(shù)作為其一個或多個參數(shù)的函數(shù)或方法時,尤其如此。

Closure表達(dá)式是一種以簡短,集中的語法編寫內(nèi)聯(lián)閉包的方法。Closure表達(dá)式提供了幾種語法優(yōu)化,用于以縮短的形式編寫閉包,而不會丟失清晰度或意圖。下面的閉包表達(dá)式示例通過sorted(by:)在幾次迭代中細(xì)化該方法的單個示例來說明這些優(yōu)化,每個迭代以更簡潔的方式表達(dá)相同的功能。

排序方法

Swift的標(biāo)準(zhǔn)庫提供了一個名為的方法sorted(by:),它根據(jù)您提供的排序閉包的輸出對已知類型的值數(shù)組進(jìn)行排序。完成排序過程后,該sorted(by:)方法返回一個與舊數(shù)組相同類型和大小的新數(shù)組,其元素按正確的排序順序排列。該sorted(by:)方法不會修改原始數(shù)組。

下面的閉包表達(dá)式示例使用該sorted(by:)方法以String反向字母順序?qū)χ禂?shù)組進(jìn)行排序。這是要排序的初始數(shù)組:

  • let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
  • 該sorted(by:)方法接受一個閉包,該閉包接受與數(shù)組內(nèi)容相同類型的兩個參數(shù),并返回一個Bool值,以說明一旦值被排序后第一個值是出現(xiàn)在第二個值之前還是之后。true如果第一個值應(yīng)出現(xiàn)在第二個值之前,則需要返回排序閉包,false否則返回。

    這個例子是對String值數(shù)組進(jìn)行排序,因此排序閉包需要是類型的函數(shù)。(String,?String)?->?Bool

    提供排序閉包的一種方法是編寫正確類型的普通函數(shù),并將其作為參數(shù)傳遞給sorted(by:)方法:

  • func backward(_ s1: String, _ s2: String) -> Bool {
  • return s1 > s2
  • }
  • var reversedNames = names.sorted(by: backward)
  • // reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
  • 如果第一個字符串(s1)大于第二個字符串(s2),則backward(_:_:)函數(shù)將返回true,表示s1應(yīng)該s2在排序數(shù)組之前出現(xiàn)。對于字符串中的字符,“大于”表示“在字母表后面出現(xiàn)”。這意味著字母"B"“大于”字母"A",字符串"Tom"大于字符串"Tim"。這給出了一個反向字母排序,"Barry"放在之前"Alex",依此類推。

    然而,這是一種相當(dāng)冗長的方式來編寫本質(zhì)上是單表達(dá)式函數(shù)()。在這個例子中,最好使用閉包表達(dá)式語法內(nèi)聯(lián)編寫排序閉包。a?>?b

    閉包表達(dá)式語法

    Closure表達(dá)式語法具有以下一般形式:

  • { (parameters) -> return type in
  • statements
  • }
  • 該參數(shù)在封閉表達(dá)式語法可以在輸出參數(shù),但是他們不能有一個默認(rèn)值。如果命名variadic參數(shù),則可以使用變量參數(shù)。元組也可以用作參數(shù)類型和返回類型。

    下面的示例顯示了backward(_:_:)上面函數(shù)的閉包表達(dá)式版本:

  • reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
  • return s1 > s2
  • })
  • 請注意,此內(nèi)聯(lián)閉包的參數(shù)聲明和返回類型與backward(_:_:)函數(shù)聲明相同。在這兩種情況下,它都寫成。但是,對于內(nèi)聯(lián)閉包表達(dá)式,參數(shù)和返回類型寫在花括號內(nèi),而不是在花括號內(nèi)。(s1:?String,?s2:?String)?->?Bool

    關(guān)閉的主體的開頭由in關(guān)鍵字引入。這個關(guān)鍵字表示閉包的參數(shù)和返回類型的定義已經(jīng)完成,閉包的主體即將開始。

    由于封蓋的主體很短,甚至可以寫在一行上:

  • reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
  • 這說明對sorted(by:)方法的整體調(diào)用保持不變。一對括號仍然包裝該方法的整個參數(shù)。但是,該參數(shù)現(xiàn)在是內(nèi)聯(lián)閉包。

    從上下文中推斷類型

    因為排序閉包作為參數(shù)傳遞給方法,所以Swift可以推斷出它的參數(shù)類型以及它返回的值的類型。該sorted(by:)方法是在一個字符串?dāng)?shù)組上調(diào)用的,因此它的參數(shù)必須是一個類型的函數(shù)。這意味著不需要將和類型作為閉包表達(dá)式定義的一部分來編寫。因為可以推斷出所有類型,所以也可以省略返回箭頭()和參數(shù)名稱周圍的括號:(String,?String)?->?Bool(String,?String)Bool->

  • reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
  • 在將閉包作為內(nèi)聯(lián)閉包表達(dá)式傳遞給函數(shù)或方法時,始終可以推斷出參數(shù)類型和返回類型。因此,當(dāng)閉包用作函數(shù)或方法參數(shù)時,您永遠(yuǎn)不需要以最完整的形式編寫內(nèi)聯(lián)閉包。

    盡管如此,如果您愿意,仍然可以使類型顯式化,如果它避免了代碼讀者的歧義,則鼓勵這樣做。在該sorted(by:)方法的情況下,封閉的目的是從分類發(fā)生的事實(shí)中清楚的,并且讀者可以認(rèn)為封閉可能與String值一起工作是安全的,因為它有助于分類。一串字符串。

    單表達(dá)式閉包的隱式返回

    單表達(dá)式閉包可以通過return從聲明中省略關(guān)鍵字來隱式返回單個表達(dá)式的結(jié)果,如上一個示例的此版本中所示:

  • reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
  • 這里,sorted(by:)方法參數(shù)的函數(shù)類型清楚地表明Bool閉包必須返回一個值。因為閉包的主體包含一個返回值的表達(dá)式(),所以沒有歧義,可以省略關(guān)鍵字。s1?>?s2Boolreturn

    速記參數(shù)名稱

    雨燕自動提供速記參數(shù)名內(nèi)聯(lián)閉包,它可以使用的名稱,指的是關(guān)閉的參數(shù)值$0,$1,$2,等等。

    如果在閉包表達(dá)式中使用這些簡寫參數(shù)名稱,則可以從其定義中省略閉包的參數(shù)列表,并且將從期望的函數(shù)類型推斷縮寫參數(shù)名稱的數(shù)量和類型。的in關(guān)鍵字也可以被省略,因為封閉件表達(dá)是由完全其身體的:

  • reversedNames = names.sorted(by: { $0 > $1 } )
  • 在這里,$0并$1參考閉包的第一個和第二個String參數(shù)。

    操作員方法

    實(shí)際上有一種更短的方式來編寫上面的閉包表達(dá)式。Swift的String類型將其大于運(yùn)算符(>)的字符串特定實(shí)現(xiàn)定義為具有兩個類型參數(shù)的方法String,并返回type的值Bool。這與方法所需的方法類型完全匹配sorted(by:)。因此,您可以簡單地傳入大于運(yùn)算符,Swift將推斷您要使用其特定于字符串的實(shí)現(xiàn):

  • reversedNames = names.sorted(by: >)
  • 欲了解更多有關(guān)操作方法,請參閱操作方法。

    尾隨閉包

    如果需要將閉包表達(dá)式作為函數(shù)的最終參數(shù)傳遞給函數(shù),并且閉包表達(dá)式很長,則將其寫為尾隨閉包可能很有用。在函數(shù)調(diào)用的括號之后寫入尾隨閉包,即使它仍然是函數(shù)的參數(shù)。使用尾隨閉包語法時,不要將閉包的參數(shù)標(biāo)簽寫為函數(shù)調(diào)用的一部分。

  • func someFunctionThatTakesAClosure(closure: () -> Void) {
  • // function body goes here
  • }
  • // Here's how you call this function without using a trailing closure:
  • someFunctionThatTakesAClosure(closure: {
  • // closure's body goes here
  • })
  • // Here's how you call this function with a trailing closure instead:
  • someFunctionThatTakesAClosure() {
  • // trailing closure's body goes here
  • }
  • 上面的Closure Expression Syntax部分中的字符串排序閉可以sorted(by:)作為尾隨閉包寫在方法的括號之外:

  • reversedNames = names.sorted() { $0 > $1 }
  • 如果提供閉包表達(dá)式作為函數(shù)或方法的唯一參數(shù),并且您將該表達(dá)式作為尾隨閉包提供,則()在調(diào)用函數(shù)時,不需要在函數(shù)或方法的名稱后面寫一對括號:

  • reversedNames = names.sorted { $0 > $1 }
  • 當(dāng)閉包足夠長以至于無法將其內(nèi)聯(lián)寫入單行時,尾隨閉包最有用。作為一個例子,Swift的Array類型有一個map(_:)方法,它將一個閉包表達(dá)式作為它的單個參數(shù)。對數(shù)組中的每個項調(diào)用一次閉包,并為該項返回一個替代映射值(可能是某些其他類型)。映射的性質(zhì)和返回值的類型留給要指定的閉包。

    將提供的閉包應(yīng)用于每個數(shù)組元素后,該map(_:)方法返回一個包含所有新映射值的新數(shù)組,其順序與原始數(shù)組中的相應(yīng)值相同。

    以下是如何使用map(_:)帶尾隨閉包的方法將Int值數(shù)組轉(zhuǎn)換為值數(shù)組String。該數(shù)組用于創(chuàng)建新數(shù)組:[16,?58,?510]["OneSix",?"FiveEight",?"FiveOneZero"]

  • let digitNames = [
  • 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
  • 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
  • ]
  • let numbers = [16, 58, 510]
  • 上面的代碼創(chuàng)建了整數(shù)位和其名稱的英語版本之間的映射字典。它還定義了一個整數(shù)數(shù)組,可以轉(zhuǎn)換為字符串。

    您現(xiàn)在可以使用numbers數(shù)組創(chuàng)建String值數(shù)組,方法是將閉包表達(dá)式map(_:)作為尾隨閉包傳遞給數(shù)組的方法:

  • let strings = numbers.map { (number) -> String in
  • var number = number
  • var output = ""
  • repeat {
  • output = digitNames[number % 10]! + output
  • number /= 10
  • } while number > 0
  • return output
  • }
  • // strings is inferred to be of type [String]
  • // its value is ["OneSix", "FiveEight", "FiveOneZero"]
  • 該map(_:)方法為數(shù)組中的每個項調(diào)用一次閉包表達(dá)式。您不需要指定閉包的輸入?yún)?shù)number的類型,因為可以從要映射的數(shù)組中的值推斷出類型。

    在此示例中,number使用closure的number參數(shù)值初始化變量,以便可以在閉包體內(nèi)修改該值。(函數(shù)和閉包的參數(shù)總是常量。)閉包表達(dá)式還指定了返回類型String,以指示將存儲在映射的輸出數(shù)組中的類型。

    閉包表達(dá)式構(gòu)建一個output每次調(diào)用時調(diào)用的字符串。它number使用余數(shù)運(yùn)算符()計算最后一位數(shù),并使用該數(shù)字在字典中查找相應(yīng)的字符串。閉包可用于創(chuàng)建任何大于零的整數(shù)的字符串表示。number?%?10digitNames

    注意

    對digitNames字典下標(biāo)的調(diào)用后跟一個感嘆號(!),因為字典下標(biāo)返回一個可選值,表示如果該鍵不存在,字典查找可能會失敗。在上面的示例中,保證始終是字典的有效下標(biāo)鍵,因此使用感嘆號強(qiáng)制解包存儲在下標(biāo)的可選返回值中的值。number?%?10digitNamesString

    從檢索到的字符串digitNames辭典被添加到前面的output,有效地建立反向一數(shù)目的字符串版本。(表達(dá)式給出for?,for?和for的值。)number?%?106168580510

    number然后將變量除以10。因為它是一個整數(shù),所以它在分割期間向下舍入,因此16變?yōu)?,58變?yōu)?,510變?yōu)?1。

    重復(fù)該過程直到number等于0,此時output字符串由閉包返回,并通過該map(_:)方法添加到輸出數(shù)組。

    在上面的示例中使用尾隨閉包語法在閉包支持的函數(shù)之后立即巧妙地封裝了閉包的功能,而無需將整個閉包包裝在map(_:)方法的外括號中。

    捕捉價值觀

    閉包可以從定義它的周圍上下文中捕獲常量和變量。然后閉包可以引用并修改其體內(nèi)的常量和變量的值,即使定義常量和變量的原始范圍不再存在。

    在Swift中,可以捕獲值的最簡單形式的閉包是嵌套函數(shù),寫在另一個函數(shù)體內(nèi)。嵌套函數(shù)可以捕獲其外部函數(shù)的任何參數(shù),還可以捕獲外部函數(shù)中定義的任何常量和變量。

    這是一個調(diào)用函數(shù)的示例makeIncrementer,其中包含一個名為的嵌套函數(shù)incrementer。嵌套incrementer()函數(shù)捕獲兩個值,runningTotal并且amount,從它的周圍環(huán)境。捕獲這些值后,incrementer將makeIncrementer作為一個閉包返回runningTotal,amount每次調(diào)用時它都會遞增。

  • func makeIncrementer(forIncrement amount: Int) -> () -> Int {
  • var runningTotal = 0
  • func incrementer() -> Int {
  • runningTotal += amount
  • return runningTotal
  • }
  • return incrementer
  • }
  • 返回類型makeIncrementer是。這意味著它返回一個函數(shù),而不是一個簡單的值。它返回的函數(shù)沒有參數(shù),每次調(diào)用時都返回一個值。要了解函數(shù)如何返回其他函數(shù),請參見函數(shù)類型作為返回類型()?->?IntInt

    該makeIncrementer(forIncrement:)函數(shù)定義了一個名為的整數(shù)變量runningTotal,用于存儲將返回的增量器的當(dāng)前運(yùn)行總數(shù)。此變量初始化為值0。

    該makeIncrementer(forIncrement:)函數(shù)有一個Int參數(shù)標(biāo)簽為forIncrement的參數(shù),參數(shù)名稱為amount。傳遞給此參數(shù)的參數(shù)值指定runningTotal每次調(diào)用返回的增量函數(shù)時應(yīng)遞增多少。該makeIncrementer函數(shù)定義了一個名為的嵌套函數(shù)incrementer,它執(zhí)行實(shí)際的遞增。此功能只是增加了amount對runningTotal,并返回結(jié)果。

    單獨(dú)考慮時,嵌套incrementer()函數(shù)可能看起來不常見:

  • func incrementer() -> Int {
  • runningTotal += amount
  • return runningTotal
  • }
  • 該incrementer()函數(shù)沒有任何參數(shù),但它在其函數(shù)體內(nèi)引用runningTotal和引用amount。它通過捕獲做到這一點(diǎn)參考,以runningTotal和amount從周圍的功能和其自身的函數(shù)體中使用它們。通過參考捕捉保證runningTotal和amount不消失的時候調(diào)用makeIncrementer結(jié)束,而且也保證了runningTotal可用下一次incrementer函數(shù)被調(diào)用。

    注意

    作為優(yōu)化,如果該值未被閉包變異,并且在創(chuàng)建閉包后該值未發(fā)生變化,則Swift可以代之以捕獲并存儲值的副本。

    Swift還處理在不再需要變量時處理變量所涉及的所有內(nèi)存管理。

    這是一個實(shí)際的例子makeIncrementer:

  • let incrementByTen = makeIncrementer(forIncrement: 10)
  • 此示例設(shè)置一個常量incrementByTen,該常量調(diào)用以引用每次調(diào)用時添加10到其runningTotal變量的增量函數(shù)。多次調(diào)用該函數(shù)會顯示此行為:

  • incrementByTen()
  • // returns a value of 10
  • incrementByTen()
  • // returns a value of 20
  • incrementByTen()
  • // returns a value of 30
  • 如果您創(chuàng)建第二個增量器,它將擁有自己存儲的對新的單獨(dú)runningTotal變量的引用:

  • let incrementBySeven = makeIncrementer(forIncrement: 7)
  • incrementBySeven()
  • // returns a value of 7
  • incrementByTen再次調(diào)用原始增量器()會繼續(xù)增加其自己的runningTotal變量,并且不會影響由incrementBySeven以下內(nèi)容捕獲的變量:

  • incrementByTen()
  • // returns a value of 40
  • 注意

    如果為類實(shí)例的屬性分配閉包,并且閉包通過引用實(shí)例或其成員來捕獲該實(shí)例,則將在閉包和實(shí)例之間創(chuàng)建一個強(qiáng)引用循環(huán)。Swift使用捕獲列表來打破這些強(qiáng)大的參考周期。有關(guān)更多信息,請參閱閉包的強(qiáng)引用周期。

    閉包是參考類型

    在上面的例子中,incrementBySeven并且incrementByTen是常量,但這些常量引用的閉包仍然能夠增加runningTotal它們捕獲的變量。這是因為函數(shù)和閉包是引用類型。

    無論何時將函數(shù)或閉包賦值給常量或變量,實(shí)際上都是將該常量或變量設(shè)置為對函數(shù)或閉包的引用。在上面的例子中,它是閉包的選擇,它incrementByTen?引用的是常量,而不是閉包本身的內(nèi)容。

    這也意味著如果為兩個不同的常量或變量分配閉包,那么這兩個常量或變量都引用相同的閉包。

  • let alsoIncrementByTen = incrementByTen
  • alsoIncrementByTen()
  • // returns a value of 50
  • incrementByTen()
  • // returns a value of 60
  • 上面的例子顯示調(diào)用alsoIncrementByTen與調(diào)用相同incrementByTen。因為它們都引用相同的閉包,它們都會遞增并返回相同的運(yùn)行總計。

    逃離閉包

    閉包是說逃避當(dāng)封蓋作為參數(shù)傳遞給函數(shù),但在函數(shù)返回之后被調(diào)用的函數(shù)。當(dāng)聲明一個以閉包作為其參數(shù)之一的函數(shù)時,可以@escaping在參數(shù)的類型之前寫入,以指示允許閉包轉(zhuǎn)義。

    閉包可以轉(zhuǎn)義的一種方法是存儲在函數(shù)外部定義的變量中。作為示例,許多啟動異步操作的函數(shù)將閉包參數(shù)作為完成處理程序。函數(shù)在啟動操作后返回,但是在操作完成之前不會調(diào)用閉包 - 閉包需要轉(zhuǎn)義,以便稍后調(diào)用。例如:

  • var completionHandlers: [() -> Void] = []
  • func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
  • completionHandlers.append(completionHandler)
  • }
  • 該someFunctionWithEscapingClosure(_:)函數(shù)將閉包作為其參數(shù),并將其添加到在函數(shù)外部聲明的數(shù)組中。如果沒有用此標(biāo)記此函數(shù)的參數(shù)@escaping,則會出現(xiàn)編譯時錯誤。

    使用@escaping意味著self在閉包中明確引用的方法標(biāo)記閉包。例如,在下面的代碼中,傳遞給的閉包someFunctionWithEscapingClosure(_:)是一個轉(zhuǎn)義閉包,這意味著它需要self顯式引用。相反,傳遞給的閉包someFunctionWithNonescapingClosure(_:)是一個非自動閉包,這意味著它可以self隱含地引用。

  • func someFunctionWithNonescapingClosure(closure: () -> Void) {
  • closure()
  • }
  • class SomeClass {
  • var x = 10
  • func doSomething() {
  • someFunctionWithEscapingClosure { self.x = 100 }
  • someFunctionWithNonescapingClosure { x = 200 }
  • }
  • }
  • let instance = SomeClass()
  • instance.doSomething()
  • print(instance.x)
  • // Prints "200"
  • completionHandlers.first?()
  • print(instance.x)
  • // Prints "100"
  • Autoclosures

    一個autoclosure是自動創(chuàng)建來包裝被真實(shí)作為參數(shù)傳遞給函數(shù)的表達(dá)式的封閉件。它不接受任何參數(shù),當(dāng)它被調(diào)用時,它返回包含在其中的表達(dá)式的值。這種語法方便使您可以通過編寫普通表達(dá)式而不是顯式閉包來省略函數(shù)參數(shù)周圍的大括號。

    這是常見的來電稱取autoclosures的功能,但它不是常見的實(shí)現(xiàn)那種功能。例如,該assert(condition:message:file:line:)函數(shù)為其condition和message參數(shù)采用autoclosure?;?它c(diǎn)ondition僅在調(diào)試參數(shù)進(jìn)行評估,并建立其message僅在參數(shù)評估condition是false。

    autoclosure允許您延遲評估,因為在您調(diào)用閉包之前,內(nèi)部代碼不會運(yùn)行。延遲評估對于具有副作用或計算成本高昂的代碼非常有用,因為它可以讓您控制何時評估該代碼。下面的代碼顯示了關(guān)閉延遲評估的方式。

  • var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
  • print(customersInLine.count)
  • // Prints "5"
  • let customerProvider = { customersInLine.remove(at: 0) }
  • print(customersInLine.count)
  • // Prints "5"
  • print("Now serving \(customerProvider())!")
  • // Prints "Now serving Chris!"
  • print(customersInLine.count)
  • // Prints "4"
  • 即使customersInLine數(shù)組的第一個元素被閉包內(nèi)的代碼刪除,在實(shí)際調(diào)用閉包之前不會刪除數(shù)組元素。如果從不調(diào)用閉包,則永遠(yuǎn)不會計算閉包內(nèi)的表達(dá)式,這意味著永遠(yuǎn)不會刪除數(shù)組元素。請注意,類型customerProvider是不是String,但不帶任何參數(shù),返回一個字符串-a功能。()?->?String

    當(dāng)您將閉包作為參數(shù)傳遞給函數(shù)時,您會得到與延遲求值相同的行為。

  • // customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
  • func serve(customer customerProvider: () -> String) {
  • print("Now serving \(customerProvider())!")
  • }
  • serve(customer: { customersInLine.remove(at: 0) } )
  • // Prints "Now serving Alex!"
  • serve(customer:)上面列表中的函數(shù)采用顯式閉包,返回客戶的名稱。下面的版本serve(customer:)執(zhí)行相同的操作,但不是采用顯式閉包,而是通過使用@autoclosure屬性標(biāo)記其參數(shù)的類型來進(jìn)行自動閉包。現(xiàn)在你可以調(diào)用該函數(shù),就好像它使用了一個String參數(shù)而不是一個閉包。參數(shù)自動轉(zhuǎn)換為閉包,因為customerProvider參數(shù)的類型用@autoclosure屬性標(biāo)記。

  • // customersInLine is ["Ewa", "Barry", "Daniella"]
  • func serve(customer customerProvider: @autoclosure () -> String) {
  • print("Now serving \(customerProvider())!")
  • }
  • serve(customer: customersInLine.remove(at: 0))
  • // Prints "Now serving Ewa!"
  • 注意

    過度使用autoclosures會使您的代碼難以理解。上下文和函數(shù)名稱應(yīng)該明確表示正在推遲評估。

    如果您想要允許轉(zhuǎn)義的autoclosure,請使用@autoclosure和@escaping屬性。@escaping上面的Escaping Closures中描述了該屬性。

  • // customersInLine is ["Barry", "Daniella"]
  • var customerProviders: [() -> String] = []
  • func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
  • customerProviders.append(customerProvider)
  • }
  • collectCustomerProviders(customersInLine.remove(at: 0))
  • collectCustomerProviders(customersInLine.remove(at: 0))
  • print("Collected \(customerProviders.count) closures.")
  • // Prints "Collected 2 closures."
  • for customerProvider in customerProviders {
  • print("Now serving \(customerProvider())!")
  • }
  • // Prints "Now serving Barry!"
  • // Prints "Now serving Daniella!"
  • 在上面的代碼中,函數(shù)將閉包附加到數(shù)組,而不是調(diào)用作為customerProvider參數(shù)傳遞給它c(diǎn)ollectCustomerProviders(_:)的閉包c(diǎn)ustomerProviders。數(shù)組聲明在函數(shù)范圍之外,這意味著在函數(shù)返回后可以執(zhí)行數(shù)組中的閉包。因此,customerProvider必須允許參數(shù)的值轉(zhuǎn)義函數(shù)的作用域。

    轉(zhuǎn)載于:https://www.cnblogs.com/strengthen/p/9728063.html

    總結(jié)

    以上是生活随笔為你收集整理的Swift5.1 语言指南(九) 闭包的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。