Swift:閉包

來源:互聯網
上載者:User

標籤:rem   列印   string類   輕量   期望   closure   函數實現   操作   int   

一、閉包的介紹
  • 閉包運算式(Closure Expressions)
  • 尾隨閉包(Trailing Closures)
  • 值捕獲(Capturing Values)
  • 閉包是參考型別(Closures Are Reference Types)

閉包是自包含的函數代碼塊,可以在代碼中被傳遞和使用。 Swift 中的閉包與 C 和 Objective-C 中的代碼塊(blocks)以及其他一些程式設計語言中的 lambdas 函數比較相似。

閉包可以捕獲和儲存其所在上下文中任意常量和變數的引用。 這就是所謂的閉合并包裹著這些常量和變數,俗稱閉包。Swift 會為您管理在捕獲過程中涉及到的所有記憶體操作。

全域和嵌套函數實際上也是特殊的閉包,閉包採取如下三種形式之一:

  • 全域函數是一個有名字但不會捕獲任何值的閉包
  • 嵌套函數是一個有名字並可以捕獲其封閉函數域內值的閉包
  • 閉包運算式是一個利用輕量級文法所寫的可以捕獲其上下文中變數或常量值的匿名閉包

Swift 的閉包運算式擁有簡潔的風格,並鼓勵在常見情境中進行文法最佳化,主要最佳化如下:

  • 利用上下文推斷參數和傳回值類型
  • 隱式返回單運算式閉包,即單運算式閉包可以省略return關鍵字
  • 參數名稱縮寫
  • 尾隨(Trailing)閉包文法

 

二、樣本

1、sorted 函數,sorted函數需要傳入兩個參數:

已知類型的數組,閉包函數,該閉包函數需要傳入與數群組類型相同的兩個值,並返回一個布爾類型值來告訴sorted函數當排序結束後傳入的第一個參數排在第二個參數前面還是後面。如果第一個參數值出現在第二個參數值前面,排序閉包函數需要返回true,反之返回false

這是一個相當冗長的方式,本質上只是寫了一個單運算式函數 (a > b)

let names = ["Chris","Alex","Ewa","Barry","Daniella"]func backwards(s1:String, s2:String) -> Bool{    return s1 > s2}var reverse = names.sort(backwards)print("降序:\(reverse)")

2、閉包運算式文法

閉包運算式文法有如下一般形式

{ (parameters) -> returnType in

    statements

}

閉包運算式文法可以使用常量、變數和inout類型作為參數,不提供預設值。 也可以在參數列表的最後使用可變參數。 元組也可以作為參數和傳回值。

reverse = names.sort({ (s1:String, s2:String) ->Bool in return s1 < s2 })print("升序:\(reverse)")

3、根據上下文推斷類型

因為排序閉包函數是作為sorted函數的參數進行傳入的,Swift可以推斷其參數和傳回值的類型。 sorted期望第二個參數是類型為(String, String) -> Bool的函數,因此實際上String,String和Bool類型並不需要作為閉包運算式定義中的一部分。 因為所有的類型都可以被正確推斷,返回箭頭 (->) 和圍繞在參數周圍的括弧也可以被省略:

實際上任何情況下,通過內聯閉包運算式構造的閉包作為參數傳遞給函數時,都可以推斷出閉包的參數和傳回值類型,這意味著您幾乎不需要利用完整格式構造任何內聯閉包。

reverse = names.sort({s1,s2 in return s1 > s2})print("降序:\(reverse)")

4、單運算式閉包隱式返回

單行運算式閉包可以通過隱藏return關鍵字來隱式返回單行運算式的結果,如上版本的例子可以改寫為

在這個例子中,sorted函數的第二個參數函數類型明確了閉包必須返回一個Bool類型值。 因為閉包函數體只包含了一個單一運算式 (s1 > s2),該運算式返回Bool類型值,因此這裡沒有歧義,return關鍵字可以省略。

reverse = names.sort({s1,s2 in s1 < s2})print("升序:\(reverse)")

5、參數名稱縮寫

Swift 自動為內嵌函式提供了參數名稱縮寫功能,您可以直接通過$0,$1,$2來順序調用閉包的參數。

如果您在閉包運算式中使用參數名稱縮寫,您可以在閉包參數列表中省略對其的定義,並且對應參數名稱縮寫的類型會通過函數類型進行推斷。 in關鍵字也同樣可以被省略,因為此時閉包運算式完全由閉包函數體構成:

reverse = names.sort({ $0 > $1 })//在這個例子中,$0和$1表示閉包中第一個和第二個String類型的參數。print("降序:\(reverse)")

6、運算子函數

實際上還有一種更簡短的方式來撰寫上面例子中的閉包運算式。 Swift 的String類型定義了關於大於符號 (>) 的字串實現,其作為一個函數接受兩個String類型的參數並返回Bool類型的值。 而這正好與sorted函數的第二個參數需要的函數類型相符合。 因此,您可以簡單地傳遞一個大於符號,Swift可以自動推斷出您想使用大於符號的字串函數實現:

reverse = names.sort( < )print("升序:\(reverse)")

7、尾隨閉包

如果您需要將一個很長的閉包運算式作為最後一個參數傳遞給函數,可以使用尾隨閉包來增強函數的可讀性。 尾隨閉包是一個書寫在函數括弧之後的閉包運算式,函數支援將其作為最後一個參數調用。

func someFunctionThatTakesAClosure(closure: () -> ()) {    // 函數體部分    closure()}
//以下是不使用尾隨閉包進行函數調用someFunctionThatTakesAClosure({    //閉包主體部分    print("first:closure閉包函數被調用了")})//以下是使用尾隨閉包進行函數調用someFunctionThatTakesAClosure {    //閉包主體部分    print("second:closure閉包函數被調用了")}

注意: 如果函數只需要閉包運算式一個參數,當您使用尾隨閉包時,您甚至可以把()省略掉。

例如:reverse = names.sort({ $0 > $1 })

當閉包非常長以至於不能在一行中進行書寫時,尾隨閉包變得非常有用。 舉例來說,Swift 的Array類型有一個map方法,其擷取一個閉包運算式作為其唯一參數。 數組中的每一個元素調用一次該閉包函數,並返回該元素所映射的值(也可以是不同類型的值)。 具體的映射方式和傳回值類型由閉包來指定。

當提供給數組閉包函數後,map方法將返回一個新的數組,數組中包含了與原數組一一對應的映射後的值。

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]func printOutput() -> Void {        let strings = numbers.map {        (var number) -> String in        var output = ""        while number > 0 {            output = digitNames[number % 10]! + output            number /= 10        }        return output    }    print(strings)}printOutput()

8、捕獲值

閉包可以在其定義的上下文中捕獲常量或變數。 即使定義這些常量和變數的原域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。

Swift最簡單的閉包形式是嵌套函數,也就是定義在其他函數的函數體內的函數。 嵌套函數可以捕獲其外部函數所有的參數以及定義的常量和變數。

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

注意: Swift 會決定捕獲引用還是拷貝值。 您不需要標註amount或者runningTotal來聲明在嵌入的incrementor函數中的使用方式。 Swift 同時也處理runingTotal變數的記憶體管理操作,如果不再被incrementor函數使用,則會被清除。

let incrementByTen = makeIncrementor(forIncrement: 10)print(incrementByTen())print(incrementByTen())print(incrementByTen())
 三、列印結果:
降序:["Ewa", "Daniella", "Chris", "Barry", "Alex"]升序:["Alex", "Barry", "Chris", "Daniella", "Ewa"]降序:["Ewa", "Daniella", "Chris", "Barry", "Alex"]升序:["Alex", "Barry", "Chris", "Daniella", "Ewa"]降序:["Ewa", "Daniella", "Chris", "Barry", "Alex"]升序:["Alex", "Barry", "Chris", "Daniella", "Ewa"]first:closure閉包函數被調用了second:closure閉包函數被調用了["OneSix", "FiveEight", "FiveOneZero"]102030

 

Swift:閉包

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.