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
上一篇: Swift函數 下一篇: Swift枚舉