- 原文地址:What’s New in Swift 5.3?
- 原文做者:Anupam Chugh
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:chaingangway
- 校对者:chaingangway、Zorro
支持跨平台,多个尾随闭包,多模式 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
当前,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]
复制代码
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)
}
复制代码
在 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
子句。
在 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
属性观察器的 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]
复制代码
SE-0277 提出了 Float16
—— 半精度浮点类型。随着近年来机器学习在移动设备上的出现,苹果公司在这一领域表现了其雄心壮志。Float16
一般用于移动设备上的 GPU 计算,并做为 ML 程序中权重的压缩格式。
let f16: Float16 = 7.29
复制代码
咱们已经总结了 Swift 5.3 语言重要的新功能,Swift 包管理器也进行了不少改进。让咱们快速浏览一下它们:
您能够在这个博客下载 Swift 的 Linux 发行版。或者您能够直接访问 Swift 的官网快速浏览 Swift 5.3 的快照版本。
本文结束。谢谢阅读。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。