Swift Closures(閉包)


Swift 4中的Closures(閉包)類似於組織為塊的自包含函式,並且像C和Objective C語言一樣呼叫。 在函式內定義的常數和變數參照被捕獲並儲存在閉包中。 函式可以看作是閉包的特殊情況,它採用以下三種形式 -

全域性函式 巢狀函式 閉包表示式
有名稱,不捕獲任何值 有名稱,從封閉函式中捕獲值。 未命名的閉包從相鄰塊中捕獲值

Swift 4語言中的Closures(閉包)表示式遵循清晰,優化和輕量級的語法風格,包括 -

  • 從上下文中推斷引數和返回值型別。
  • 單表示式閉包的隱式返回。
  • 速記引數名稱。
  • 尾隨閉包語法。

語法
以下是定義閉包的通用語法,此閉包接受引數並返回資料型別 -

{
   (parameters) ?> return type in
   statements
}

以下是一個簡單的例子 -

let studname = { print("Welcome to Swift Closures") }
studname()

當使用playground執行上述程式時,得到以下結果 -

Welcome to Swift Closures

以下閉包接受兩個引數並返回Bool型別值 -

{     
   (Int, Int) ?> Bool in
   Statement1
   Statement 2
   ---
   Statement n
}

以下是一個簡單的例子 -

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

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

當使用playground執行上述程式時,得到以下結果 -

10

閉包中的表示式

巢狀函式提供了一種命名和定義程式碼塊的便捷方式。 但它不是表示整個函式宣告和名稱構造,它用於表示更短的函式。 通過閉包表示式實現在具有集中語法的清晰簡短語句中表示函式。

升序排序程式

對字串進行排序是通過Swift 4鍵保留函式sorted實現的,該函式已在標準庫中提供實現。 它將按升序對給定字串進行排序,並返回具有舊陣列中提到的相同大小和資料型別的新陣列中的元素。 舊陣列保持不變。

在排序函式中表示兩個引數 -

  • 已知型別的值表示為陣列。
  • 陣列內容(Int,Int)並返回一個布林值(Bool)如果陣列正確排序,它將返回true值,否則返回false

編寫帶有輸入字串的普通函式並將其傳遞給已排序函式,以將字串排序為新陣列,如下所示 -

func ascend(s1: String, s2: String) -> Bool {
   return s1 > s2
}

let stringcmp = ascend(s1: "Swift 4", s2: "great")
print (stringcmp)

使用playground執行上述程式時,得到以下結果 -

true

要為icecream初始陣列元素值為「Swift 4」「great」。 將陣列排序的函式宣告為字串資料型別,返回型別稱為布林值。 兩個字串都按升序進行比較和排序,並儲存在一個新陣列中。 如果成功執行排序,則函式將返回true值,否則返回false值。

閉包表示式語法使用 -

  • 常數引數
  • 變數引數
  • inout引數

Closure表示式不支援預設值。 變數引數和元組也可以用作引數型別和返回型別。

let sum = {
   (no1: Int, no2: Int) -> Int in 
   return no1 + no2 
}

let digits = sum(30, 20)
print(digits)

使用playground執行上述程式時,得到以下結果 -

50

函式語句中提到的引數和返回型別宣告也可以用帶有in關鍵字的內聯閉包表示式函式表示。 宣告引數和返回型別in關鍵字用於表示閉包的主體。

單表示式隱式返回

這裡,sorted函式的第二個引數的函式型別清楚地表明閉包必須返回一個Bool值。 因為閉包的主體包含一個返回Bool值的表示式(s1> s2),所以沒有歧義,並且可以省略return關鍵字。

要在表示式中返回單表示式語句,請在其宣告部分中省略return關鍵字。

var count:[Int] = [5, 10, -6, 75, 20]
let descending = count.sorted(by: { n1, n2 in n1 > n2 })
let ascending = count.sorted(by: { n1, n2 in n1 < n2 })

print(descending)
print(ascending)

使用playground執行上述程式時,得到以下結果 -

[75, 20, 10, 5, -6]
[-6, 5, 10, 20, 75]

語句本身清楚地定義當string1大於string2時返回true,否則返回false,因此這裡省略return語句。

已知型別閉包

考慮兩個數位相加,相減將返回整數資料型別。 因此,已知的型別閉包被宣告為 -

let sub = {
   (no1: Int, no2: Int) -> Int in 
   return no1 - no2 
}

let digits = sub(10, 20)
print(digits)

使用playground執行上述程式時,得到以下結果 -

-10

簡寫引數名稱宣告為閉包

Swift 4自動為內聯閉包提供簡寫引數名稱,可用於通過名稱$0$1$2等來參照閉包引數的值。

var shorthand: (String, String) -> String
shorthand = { $1 }
print(shorthand("100", "200"))

這裡,$0$1參照閉包的第一個和第二個String引數。

使用playground執行上述程式時,得到以下結果 -

200

Swift 4通過$0$1$2$n表示,便於使用者將內嵌閉包表示為簡寫引數名稱。

當在閉包表示式中表示簡寫引數名稱時,在定義部分中省略了閉包引數列表。 根據函式型別,將派生簡寫引數名稱。 由於在表示式主體中定義了速記引數,因此省略了in關鍵字。

閉包作為運算子函式

Swift 4提供了一種通過僅提供運算子函式作為閉包來存取成員的簡便方法。 在前面的範例中,關鍵字Bool用於在字串相等時返回true,否則返回false

閉包中的運算子函式使表示式更簡單 -

let numb = [98, -20, -30, 42, 18, 35]
var sortedNumbers = numb.sorted ({
   (left: Int, right: Int) -> Bool in
   return left < right
})

let asc = numb.sorted(<)
print(asc)

執行上面範例程式碼,得到以下結果 -

[-30, -20, 18, 35, 42, 98]

閉包尾隨

在「Trailing Closures」的幫助下宣告將函式的最終引數傳遞給閉包表示式。 它用{}寫在函式()之外。 當無法在單行上內聯編寫函式時,需要使用它。

reversed = sorted(names) { $0 > $1}

其中{$0 > $1}表示為在(名稱)外部宣告的尾隨閉包。

import Foundation
var letters = ["North", "East", "West", "South"]

let twoletters = letters.map({ 
   (state: String) -> String in
   return state.substringToIndex(advance(state.startIndex, 2)).uppercaseString
})

let stletters = letters.map() { 
   $0.substringToIndex(advance($0.startIndex, 2)).uppercaseString 
}
print(stletters)

執行上面範例程式碼,得到以下結果 -

[NO, EA, WE, SO]

捕獲值和參照型別

在Swift 4中,捕獲常數和變數值是在閉包的幫助下完成的。 它進一步參照和修改閉包體內的那些常數和變數的值,即使變數不再存在。

通過在其他函式的主體中編寫函式來使用巢狀函式來捕獲常數和變數值。

巢狀函式捕獲 -

  • 外部函式引數。
  • 捕獲外部函式中定義的常數和變數。

在Swift 4中,當在函式內宣告常數或變數時,閉包也會自動建立對這些變數的參照。 它還提供了將兩個以上變數作為同一個閉包參照的工具,如下所示 -

let decrem = calcDecrement(forDecrement: 18)
decrem()

這裡的forDecrementdecrem變數都指向與閉包參照相同的記憶體塊。

func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 100
   func decrementer() -> Int {
      overallDecrement -= total
      print(overallDecrement)
      return overallDecrement
   }
   return decrementer
}

let decrem = calcDecrement(forDecrement: 18)
decrem()
decrem()
decrem()

執行上面範例程式碼,得到以下結果 -

82
64
46

當每次呼叫外部函式calcDecrement時,它會呼叫decrementer()函式並將值遞減18並在外部函式calcDecrement的幫助下返回結果。 這裡calcDecrement充當閉包。

即使函式decrementer()不使用任何引數,預設情況下,閉包通過捕獲其現有值來參照變數overallDecrementtotal。 指定變數的值副本與新的decrementer()函式一起儲存。 Swift 4通過在不使用變數時分配和釋放記憶體空間來處理記憶體管理功能。


以下是糾正/補充內容:

現在的Swift語法是 閉包中一定要加上by 啊,不然編譯都過不了。就是 XXX.sortedby:提交時間:2019-09-03