Swift 5.3 又更新了什么新奇爽快的语法?

Python实战社群

Java实战社群

长按识别下方二维码,按需求添加

扫码关注添加客服

进Python社群▲

扫码关注添加客服

进Java社群

作者丨蒋志远(星志)

来源丨淘系技术(AlibabaMTT)

Swift 在 WWDC14 正式发布到 2019,经过 5 年的不断迭代,这其中经历了标准库变动,语法的增减。首先使用 Swift 作为开发语言的开发者们都苦不堪言,戏称《Swift 从入门到重学》,几乎每一年 Swift 都会迎来比较大的改动,甚至 API 都发生了变化。

WWDC 19 苹果发布了 Swift 5.0,苹果终于宣布 Swift 的 ABI 稳定。这标志着 Swift 这门语言已经趋于稳定,在 2019 至 2020 的迭代中,Swift 5.2 也做到了模块稳定,之前的大修大改已经不会在出现了。

Swift 发展里程碑


有意思的是,在 WWDC16 中有一页 PPT 写下了 Goals for Swift 3:

  • Develop an open community

  • Portability to new platforms

  • Get the fundamentals right

  • Optimize for awesomenss

如今已经 2020 年,再回头看这些目标,Swift 5.3 几乎完全实现了。Swift 可谓一直不忘初心,朝着认为正确的方向不断的努力。

语法的不断成熟


每年 WWDC 比较期待的一个点就是看看 Swift 又加了一些什么新奇爽快的语法。我先列举一下 Swift 5.3 新增的语法:

  • [SE-0249] KeyPath as Function

  • [SE-0279] Multiple trailing closure

  • [SE-0281] Type-based program entry point (@main)

  • [SE-0266] Synthesized comparable conformation for enum types

  • [SE-0269] Increased availability of implicit self in closure

  • [SE-0276] Multi-pattern catch clauses

  • [SE-0280] Enum cases as protocol witnesses

  • [SE-0267] Where clauses on contextually generic declarations

  • [SE-0270] Collection operations on noncontiguous elements

  • [SE-0264] Standard library preview package

  • [SE-0253] Callable values of user-defined nominal types

  • [SE-0263] String initializer with access to uninitialized storage

上面列举的 12 个语法改动,有兴趣的同学可以到 swift-evolution 去查看详细的内容。其中比较有意思的几个改动就是 [SE-279],[SE-281]和[SE-0269],我们来细细评味一下。

 Design for SwiftUI

[SE-279] Multiple trailing closure 多重尾闭包这个新特性算是一个非常大的改动。这个特性的出现影响了 Swift 非常重要的地方,ABI 设计。先来几个官方的例子:

// 1. Single closure argument -> trailing closure
UIView.animate(withDuration: 0.3) {
  self.view.alpha = 0
}
// 2. With trailing closure
UIView.animate(withDuration: 0.3, animations: {
  self.view.alpha = 0
}) { _ in
  self.view.removeFromSuperview()
}
// 3. Multiple closure arguments -> no trailing closure
UIView.animate(withDuration: 0.3, animations: {
  self.view.alpha = 0
}, completion: { _ in
  self.view.removeFromSuperview()
})
// 4. Multiple trailing closure arguments
UIView.animate(withDuration: 0.3) {
  self.view.alpha = 0
} completion: { _ in
  self.view.removeFromSuperview()
}

上面的代码中 2 的情况是经常出现的,尾闭包的含义就不够明确,以前最佳的方式应该为 3,但是两个闭包被套在一个小括号里,使得括号多重嵌套,可读性下降。为了解决这个问题,苹果使用了第 4 中方法--多重尾闭包。可以从代码看出可读性得到了很大的提升。

这一看似优雅的设计其实引入了很多语言的复杂度,有了这个特性你甚至可以写出类似下面的代码,看上去就像是创造了一个 if-else 语句,但其实它是一个函数。

func when(
  _ condition: @autoclosure () -> Bool,
  then: () -> T,
  `else`: () -> T
) -> T {
  condition() ? then() : `else`()
}
// using syntax
when(2 < 3) {
  print("then")
} else: {
  print("else")
}
// equivalent to:
when(2 < 3, then: { print("then") }, else: { print("else") })

这就对 SDK 的开发者提出了更高的要求,需要小心的使用这个特性来设计 API,防止这个特性被滥用导致代码的可读性下降,甚至造成歧义。苹果在 WWDC20 中也强调了这一点。

还有两个特性其实很简单,[SE-0281] 是 @main 来标记程序入口,[SE-0269] 是让开发者在特定的情况下不需要再写多余的 self.。

苹果推出了这几个语言特性,就是为了让战略性的项目 SwiftUI 的 API 更加简洁明了。可以看下面的例子:

@main // <- @main
struct MyApp: App {
    var body: Scene {
        WindowGroup {
            Text("Hello World!")
        }
    }
}
//------
Gauge(value: acidity, in: 3...10) {
    Image(systemName: "drop.fill")
} currentValueLabel: { // <- multiple trailing closure
    Text("\(acidity, specifier: "%.1f")")
} minimumValueLabel: {
    Text("3")
} maximumValueLabel: {
    Text("10")
}
//------
struct ContentView : View {
    var landmark: Landmark
    var body: some View {
        Button(action: {
            landmark // <- no self.
        }) {
            Text("Button")
        }
    }
}

苹果也不是第一次为了 SwiftUI 改 Swift 的语法,[SE-0255] Implicit returns from single-expression functions 就是为了让 SwiftUI 的 body 不用写 return,强化 DSL 风格。

苹果为了 SwiftUI,推出了 functionBuilder 来实现 DSL 形式的代码;为了 SwiftUI,推出了许多让它更漂亮的语法特性;为了 SwiftUI,不惜为语言引入更多的复杂度。

 下限低,上限高

Swift 的最初的设计方向就导致了它是一门下限很低上限很高,入门容易精通难,使用容易设计难的语言。它一系列的语法糖和语法设计,包括类型推断系统,都是让它成为十分亲民的语言,而它的一系列语法特性,让它在设计 API、SDK实现的时候其复杂程度也不亚于其他语言。

Swift is a general-purpose, multi-paradigm, compiled programming language developed by Apple Inc. for iOS, iPadOS, macOS, watchOS, tvOS, and Linux.

---- Wikipedia

维基百科的后半部分可能有些局限了,但是前半部分说明了它是一门多编程范式的语言,Swift 可以支持 面向对象编程(OOP),面向协议编程(OPP),声明式编程(DP),函数式编程(FP),泛型编程(GP)。

Objective-C 已经发展了这么多年,如此成熟,为什么现在苹果要开始抛开它?Objective-C 本来就是生于一个面向对象编程范式起飞的一年,与 C++ 一样为了拓展 C 命令式编程范式而诞生的语言。当时 C 语言虽然也可以实现 OOP,但是语法设计成为了限制。在当代计算机编程语言研究演进下,出现了很多编程范式的新理论,如函数式编程,元编程等等,同样 OC 可以通过它的方式来实现,但是语言的冗杂和 OOP 的设计已经不能更好的表达这些概念,就犹如纯 C 来表达OOP 一样。

苹果推出 Swift 就是为了摆脱 OC 的束缚,让它能更好的践行现代的编程理论,所以才会诞生出 SwiftUI,才会有 Combine、map/filter/reduce 等这些库和 API。类型推断和元编程的理论也让 Swift 在保留强类型的环境下还能保持如此简洁优雅,可读性强的代码。而这些是 OC 无法做到的。尝试使用 OC 对这些现代概念做表达的 SDK 都会显得十分冗杂。

现在 Swift 语法已经不会再大变,有如此现代、安全、稳定、富有想象力的语言,有什么理由不真香呢?

土壤已经肥沃


我们先通过下面的脑图感受一下 Swift 更迭到 5.3 已经取得的成就。

现在 Swift 生态环境已经自成一派,有一套完整的工具链保证开发,有更独立的标准库让它可以自由迁移,包管理让丰富了它的 SDK,同时还具有 Native 语言的各种优势。在这么多年的发展中,它的能力已经触及到了 AI、Server、Mobile Device、FaaS,强大的标准库让它甚至可以当脚本语言使用。

Swift 如今已经不再孤立无援,开源让 Swift 变得生机勃勃,合理优雅的设计和开放的态度让全球的开发者们都在不断的完善它。

在 Swift 的大生态中,包管理工具是最值得一说的。一门语言它的能力,取决于它是否有强有力的 SDK,还有就是获取他们的途径。基础的 Swift 的能力都由工具链和标准库提供,而强有力的 SDK 最好的方式就是通过包管理工具快速获取。Swift Package Manager 就是 Swift 的军械库。

  Swift Package Manager

看一下 Swift Package Manager(SPM) 的发展历程,SPM 从 Swift 3.0 时就发布,当时只支持 Git 远端仓库,支持支源码发布。WWDC 19,Xcode 引入了一个新的架构 XCFramework,一个旨在能打包多个平台 framework 的文件结构。WWDC20 SPM 宣布正式支持发布二进制 framework。

WWDC20 SPM 走出的这一步标志着功能的完善。为什么这么说,因为在 iOS 届,解决了 Xcode 无包管理工具难题,让众多优秀的开源库能被快速获取的包管理工具 -- Cocoapods。在 SPM 出现之前,Cocoapods 的功能已经非常完善,打败了当时另外的一款包管理工具 Carthage。

Cocoapods 作为基于 Xcode 开发的第三方包管理工具,通过修改 Xcode 的工程信息来实现处理各个包的依赖问题。它支持依赖的二进制分发、源代码分发,基于 framework 良好的资源管理。现在许多公司的大型 App 也是用 Cocoapods 做模块化组件分离,通过二进制依赖的方式来提高打包速度。

然而比较可惜的是它工作流是脱离 Xcode 的,Podfile 更新等操作都是在工程之外。语言使用的是 Ruby,虽然使用了一些操作使 Podfile 变成了 DSL,但是对于开发者而言是有一定门槛的,特别是需要编辑发布 SDK 所使用的 podspec 时,对照文档,无代码提示的编写让写正确配置文件都成了难事。Cocoapods 还不得不设计出 podspec lint 来帮组开发者确认这个事情。

对于 Swift PM 这个亲儿子而言,就不存在这个问题,SPM 已经深入的集成到了 Xcode 中,所有的操作都可以利用 Xcode 完成。在编写 Swift Package 时,Xcode 现在已经具备将 Package.swift 作为工程项目打开,并且现在工程模板中已经包含了 Swift Package。强大的 Xcode 自动补全让编写 Package.swift 不再是一件难事。如果脱离 Xcode,利用 swift-lsp 结合现在热门的文本编辑器,如 VSCode 等都可以实现相应的功能。SPM 现在已经是独立于 Xcode 的存在,可以为 Swift 提供强有力的支持。

SPM 在功能层面已经不逊于 Cocoapods,在 WWDC20 时,SPM 已经支持以二进制库形式分发 Package,SPM 也可以管理包中的资源和本地化,基本的能力已经与 Cocoapods 差异不大,然而最关键的是,SPM 是纯 Swift ,开源,还有苹果官方支持的包管理工具。

 新瓶酿酒酒更香

国外的不少 APP 已经迁移到了 Swift;三方开源库如 AFNetworking 已经用 Swift 重写为 Alamofire,Lottie 已经完全被 Swift 重写替代。苹果也推出了许多 Swift Only 的库。苹果也在利用 Swift 为 UIKit,GCD 等基础库不断提供更具有表现力的 API。

Uber 完成了迁移,收获了 Swift 极强的稳定性。Alamofire,SnapKit 用  Swift 重写,获得了更加具有表现力的 API,开发者更容易接受且喜爱。Reactive 系列的编程风格在 Swift 上大放异彩。

机会与展望


现在 Swift 发展了这么多年,遍地开花,Objective-C 已经有在逐渐被废弃的趋势。现在很有可能都很难招到认真学习过 OC 的应届生了。

Swift 在集团内部的发展,还有很多的工作要做,这其中充满了挑战。我们也在积极探索 Swift 在手淘的落地,取得了 Swift 5.1 能模块在手淘中正确运行起来的阶段性成就。但是比较遗憾的是还有很多模块是无法让 Swift 正确跑起来的,以现在的工具链来说甚至源码依赖调试都无法做到。

但是这都是暂时的,现在时机已经成熟,Swift的语言特性,SPM,工具链,标准库都已经足够强大。未来,我们会尽快大力升级 Swift 的基建。让 Swift 的花在集团内开起。先定个小目标,希望 Swift 能成为集团 iOS 客户端开发的首选语言。

参考

  • SwiftUI 背后那些事儿

  • WWDC20 What's new in Swift

  • WWDC19 What's new in Swift

  • WWDC18 What's new in Swift

  • WWDC17 What's new in Swift

  • WWDC16 What's new in Swift

  • WWDC20 Swift packages: Resources and localization

  • WWDC20 What's new in SwiftUI

  • Swift 5 时代的机遇与挑战到底在哪里?

  • Swift Evolution

程序员专栏 扫码关注填加客服 长按识别下方二维码进群

近期精彩内容推荐:  

 写外挂赚12万获刑,被抓才知道帮团队赚300万

 程序员高薪盛宴背后:程序员正在消失?

 教你构建 Python 编程的核心知识体系!

 分享史上Java最牛逼,最简短的代码

在看点这里好文分享给更多人↓↓

你可能感兴趣的:(Swift 5.3 又更新了什么新奇爽快的语法?)