Swift 5.3 的新功能,你瞭解嗎?

Swift 5.3 的新功能,你瞭解嗎?

支持跨平臺,多個尾隨閉包,多模式 catch 子句等等前端

Swift 5.3 的發佈流程始於三月底,直到最近才進入最後的開發階段。該版本的主要目標之一是擴展語言支持 Windows 和 Linux 平臺。linux

蘋果公司也很是注重改善語言的綜合性能,以提高 SwiftUI 和 iOS 中機器學習的表現。讓咱們來仔細研究一下即將發佈的新版本中有哪些重要更新。android

多個尾隨閉包

SE-0279 提案中提出了新的尾隨閉包語法,使您能夠用更容易理解的方式將多個閉包做爲函數的參數進行調用。這是一種更增強大的語法糖,可最大程度地減小在函數簽名中使用過多括號。ios

它容許您在初始未帶標籤的閉包以後附加幾個帶標籤的閉包。如下示例演示了這種用法:git

//old
UIView.animate(withDuration: 0.5, animations: {
  self.view.alpha = 0
}, completion: { _ in
  self.view.removeFromSuperview()
})

//new multiple trailing closures
UIView.animate(withDuration: 0.5) {
            self.view.alpha = 0
        } completion: { _ in
            self.view.removeFromSuperview()
        }
複製代碼

上面的語法變化能讓 SwiftUI 視圖更容易編寫。github

多模式 catch 子句

當前,do-catch 語句中的每一個 catch 子句只能包含一個模式。要解決此問題,開發人員在 catch 語句的主體中最好使用 swtich case 語句,但這樣會增長嵌套和重複的代碼。swift

SE-0276 是另外一個很好的改進,它容許 catch 字句進行模式匹配。Catch 子句將容許用戶指定逗號分隔的模式列表,並將變量與 catch 主體綁定,就像 switch 語句同樣。下面是例子:後端

enum NetworkError: Error {
    case failure, timeout
}

//old
func networkCall(){
  do{
    try someNetworkCall()
  }catch NetworkError.timeout{
    print("timeout")
  }catch NetworkError.failure{
    print("failure")
  }
}

//new
func networkCall(){
  do{
    try someNetworkCall()
  }catch NetworkError.failure, NetworkError.timeout{
    print("handle for both")
  }
}
複製代碼

多模式 catch 子句能讓代碼清晰簡潔。數組

實現枚舉類型的比較功能

到目前爲止,比較兩個枚舉類型還不是一件容易的事。首先必須遵照 Comparable 協議,而後實現 static fun \< 方法來決定一個枚舉類型的原始值是否小於另外一個枚舉類型的原始值。(對於 > 的狀況反之亦然)。bash

值得慶幸的是,在 SE-0266 中,咱們可讓枚舉類型遵照 Comparable 協議而沒必要顯式地實現它,只需保證枚舉是標準類型。若是枚舉類型沒有設置關聯值,enums 會根據聲明的語義順序進行比較。

下面是枚舉類型排序的例子:

enum Brightness: Comparable {
    case low(Int)
    case medium
    case high
}

([.high, .low(1), .medium, .low(0)] as [Brightness]).sorted()
// [Brightness.low(0), Brightness.low(1), Brightness.medium, Brightness.high]
複製代碼

枚舉 case 與協議相匹配

Swift 中協議匹配模型是很是嚴格的,其中規定,與協議有着相同名稱和參數的枚舉 case 是不匹配的。咱們只能手動實現,以下所示:

protocol DecodingError {
  static var fileCorrupted: Self { get }
  static func keyNotFound(_ key: String) -> Self
}

enum JSONDecodingError: DecodingError {
  case _fileCorrupted
  case _keyNotFound(_ key: String)
  static var fileCorrupted: Self { return ._fileCorrupted }
  static func keyNotFound(_ key: String) -> Self { return ._keyNotFound(key) }
}
複製代碼

SE-0280 中取消了此限制,以便在協議中的名稱與參數和枚舉 case 相同時,枚舉 case 能夠直接與協議相匹配。

protocol DecodingError {
  static var fileCorrupted: Self { get }
  static func keyNotFound(_ key: String) -> Self
}
enum JSONDecodingError: DecodingError {
  case fileCorrupted
  case keyNotFound(_ key: String)
}
複製代碼

self 不須要在每處都顯式使用

SE-0269 提案中容許咱們在不須要的時候省略 self。以前,當咱們從閉包外部捕獲值時,必須在閉包中使用 self。如今,當循環引用不太可能發生時,self 將會隱式存在。

下面的例子展現了這個更新:

struct OldView: View {

    var body: some View {
        Button(action: {
            self.sayHello()
        }) {
            Text("Press")
        }
    }
    
    func sayHello(){}
}

struct NewView: View {

    var body: some View {
        Button {
            sayHello()
        } label: {
            Text("Press")
        }
    }
    
    func sayHello(){}
}
複製代碼

使用 SwiftUI 的開發人員會很樂意接受這一點。由於視圖保存在值類型的結構體中,因此不會發生循環引用。

基於類型的程序入口

SE-0281 中容許咱們使用新的 @main 屬性,它能夠定義 app 的入口。用屬性對結構體或類進行標記可以保證它是程序進入的位置,因此你沒必要手動調用 AppDelegate.main()

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
static func main() {
        print("App will launch & exit right away.")
    }
}
複製代碼

咱們能夠認爲,在之後的版本中將棄用舊版本中特定域的屬性 @UIApplicationMain@NSApplicationMain,而推薦使用 @main

where 字句在泛型聲明上下文中的變化

到目前爲止,where 字句不能在泛型上下文內嵌聲明。好比,若是你在方法中添加 where 限制,編譯器會拋出錯誤。要解決這個問題,咱們必須建立單獨的擴展來處理特定的 where 子句。

SE-0267 中,只要引用了泛型參數,咱們就能夠實現帶有 where 字句的方法。下面是一個簡短的代碼片斷:

struct Base<T> {
    var value : T 
}

extension Base{

  func checkEquals(newValue: T) where T : Equatable{...}
  func doCompare(newValue: T) where T : Comparable{...}

}
複製代碼

經過在成員聲明上容許 where 子句,咱們能夠輕鬆建立更短,更簡潔的通用接口,而不用建立單獨的擴展。

對集合中非連續元素的新操做

當前的版本中,訪問集合中連續範圍的元素很簡單。對於數組,您只需用 [startIndex ... endIndex] 訪問。

SE-0270 中介紹了一種叫作 RangeSet 的新類型,它能夠獲取不連續索引的集合,

var numbers = Array(1...15)

// Find the indices of all the even numbers
let indicesOfEvens = numbers.subranges(where: { $0.isMultiple(of: 2) })

// Find the indices of all multiples of 3
let multiplesofThree = numbers.subranges(where: { $0.isMultiple(of: 3) })

let combinedIndexes = multiplesofThree.intersection(indicesOfEvens)
let sum = numbers[combinedIndexes].reduce(0, +)
//Sum of 6 + 12 = 18
複製代碼

使用 RangeSet,咱們能夠對集合作不少計算和操做。例如,經過使用 moveSubranges 函數,咱們能夠在數組中移動一系列索引。這樣咱們能夠很容易將數組中的全部偶數移動到數組的開頭:

let rangeOfEvens = numbers.moveSubranges(indicesOfEvens, to: numbers.startIndex)
// numbers == [2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15]
複製代碼

完善 didSet 語義

以前,不管屬性的引用是否有新的賦值,didSet 屬性觀察器的 getter 方法老是會被調用來檢索 oldValue

這個機制可能對變量影響不大,可是對於大型數組,會分配存儲空間並加載未使用的值,這個過程會影響程序性能。

SE-0268 中提出,僅在須要時纔會加載 oldValue,這將提高 didSet 屬性觀察器的效率。並且,若是隻實現了 didSet 而沒有實現 willSet,更新也會正常進行。

下面是改進版 didSet 的例子:

class A {
    var firstArray = [1,2,3] {
        didSet { print("didSet called") }
    }

    var secondArray = [1,2,3,4] {
        didSet { print(oldValue) }
    }
}

let a = A()
// This will not call the getter to fetch the oldValue of firstArray
a.firstArray = [1,2]
// This will call the getter to fetch the oldValue of secondArray
a.secondArray = [1]
複製代碼

Float16 新類型

SE-0277 提出了 Float16 —— 半精度浮點類型。隨着近年來機器學習在移動設備上的出現,蘋果公司在這一領域表現了其雄心壯志。Float16 一般用於移動設備上的 GPU 計算,並做爲 ML 程序中權重的壓縮格式。

let f16: Float16 = 7.29
複製代碼

總結

咱們已經總結了 Swift 5.3 語言重要的新功能,Swift 包管理器也進行了不少改進。讓咱們快速瀏覽一下它們:

  • SE-0271 容許您將資源(圖像,數據文件等)添加到 Swift 包中。
  • SE-0278 能夠添加本地化資源。
  • SE-0272 容許您在軟件包管理器中以二進制格式集成閉源依賴(例如 Firebase)。
  • SE-0273 使您能夠有條件地爲不一樣的目標平臺指定依賴管理器。

您能夠在這個博客下載 Swift 的 Linux 發行版。或者您能夠直接訪問 Swift 的官網快速瀏覽 Swift 5.3 的快照版本。

本文結束。謝謝閱讀。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索