Swift 5.9 新特性

Published on
Authors
Table of Contents

Xcode 15.0 beta Swift 5.9

注:Swift 5.9 目前并未正式发布,本文会在正式发布后再次更新。

if 和 switch 表达式(SE-0380

let s1 = if Bool.random() { "YES" } else { "NO" }

let s2 = switch Bool.random() {
case true: "YES"
case false: "NO"
}

值和类型参数包(SE-0393

值和类型参数,实现了对不同类型的值和类型的抽象化,这是在 Swift 中实现可变泛型的第一步。

此前,泛型函数需要固定数量的类型参数。对于有多个参数的情况,通常使用函数重载来实现。这不仅在声明上很繁琐,在调用时也受到了参数数量的限制。

而有了参数包支持任意数量的不同类型参数,而且写法更加简洁。

比如下面的示例代码演示了将不同类型的可变参数组合成元组:

struct Pair<First, Second> {
  var first: First
  var second: Second
}

// each First, each Second 是两个类型的参数包
func makePairs<each First, each Second>(
  firsts first: repeat each First, // 参数包扩展,可以传入可变参数
  seconds second: repeat each Second
) -> (repeat Pair<each First, each Second>) {
  // 从参数包扩展 first 和 second 中各取一个值构建 Pair
  // 所有的 Pair 实例构成一个元组并返回
  return (repeat Pair(first: each first, second: each second))
}

let pairs = makePairs(firsts: 1, "hello", "world", seconds: true, 1.0, false)
// 'pairs' is '(Pair(1, true), Pair("hello", 2.0), Pair("world", false))'

可丢弃的任务组(SE-0381

withTaskGroupwithThrowingTaskGroup 用于创建任务组,任务组会保留整个子任务对象及其产生的数据,直到我们使用异步迭代或者调用 next() 方法消费掉某个子任务,任务组才会丢弃子任务及其产生的数据。而且 next() 方法还有个副作用,它会暂停任务的执行。

以上缺陷导致任务组不适用于需要长时间运行的子任务,比如在服务端运行的监听任务。因此 Swift 5.9 引入了 withDiscardingTaskGroupwithThrowingDiscardingTaskGroup 来解决这个问题,它们内部创建的子任务一旦完成就会被自动丢弃和销毁。

try await withThrowingDiscardingTaskGroup() { group in
  while let newConnection = try await listeningSocket.accept() {
    group.addTask {
      handleConnection(newConnection)
    }
  }
}

宏(Macros)

Swift 5.9 引入了一个新的宏系统,用于减少样板代码和在编译期排除潜在的错误。

宏有两种表现形式:独立的宏和附属宏。独立的宏总是以 # 开头,比如下面要提到的 #email,附属宏总是以 @ 开头,比如 @Observable。如果一段代码中没有这两个标志性的符号,那么可以确定没有宏。

自定义宏必须在 Package 中实现,最新的 Xcode 15 支持创建 Swift Macro:*File > New > Package…。*Package 的目录结构如下:

├── Package.swift
├── Sources
│   ├── WWDC23
│   │   └── WWDC23.swift // 向外公开 API
│   ├── WWDC23Client
│   │   └── main.swift // 运行和测试
│   └── WWDC23Macros
│       └── WWDC23Macro.swift // 宏的实现
└── Tests
    └── WWDC23Tests
        └── WWDC23Tests.swift // 测试

新建的 Package 已经实现了一个名为 #stringify 的独立宏,并且附有完整的测试和运行代码。 我们可以仿照它写一个名为 #email 的宏来检测一个字符串是否为有效的 email 地址,具体实现见源码

根据宏的作用,它可以分为以下几类,其中前两个是独立宏,其它则为附属宏:

swift macro roles

在 SwiftUI 开发中,我们将会大量的使用新框架 Observation 中的 @Observable,它是附属宏的典型运用之一。另一个新框架 SwiftData 中的 @Model,也展现出了宏的强大和简洁。

宏非常易于使用,但实现上比较复杂。值得庆幸的是,我们可以在 Xcode 查看宏的注释,而且可以展开宏来查看宏的具体实现和进行断点调试。

关于宏的使用,有待进一步探究。

所有权(Ownership)

待更新

其它

Result builders 可以更快更准确地给出错误提示,这有利于提高 SwiftUI 代码的编写效率。

Swift Foundation 提高了关于日期、日历计算的效率,并且极大地提高了 JSON 编码的处理速度。

更多关于 Swift 5.9 的更新内容,请移步官方 CHANGELOG

twitterDiscuss on Twitter