Swift 2022 年夏季代码总结
Google 夏季代码 (也称为 GSoC) 是一项长期导师计划,专注于将贡献者引入开源开发的世界。今年是 Swift 项目第五次参与 GSoC。
在 2022 年的项目版本中,我们很幸运能与五位优秀的贡献者合作,他们都成功完成了分配的项目。我们要感谢所有贡献者 – Amritpan、Felix、Fredrik、Kth 和 Sofía – 感谢他们为项目投入的时间和热情
- 引导 SwiftSyntaxBuilder
- 改进类型推断算法的调试输出
- ArgumentParser 的交互模式
- Swift-DocC 网站中的快速导航
- Swift 的 Kafka 客户端软件包
为了彰显他们杰出的工作并激励未来的参与者,让我们仔细看看他们的成就。
引导 SwiftSyntaxBuilder
SwiftSyntax
库允许用户使用 Swift 表示、解析和生成 Swift 源代码,该库收到了重大更新。基于结果构建器的 SwiftSyntaxBuilder
领域特定语言 (DSL) 得到了改进,API 表面中的不便之处得到了修复并经过了彻底的测试。
在此过程中,生成部分 SwiftSyntaxBuilder
源代码的模板从 gyb
移植到基于 SwiftSyntaxBuilder
的类型安全 Swift 代码。换句话说,该库现在使用自身来生成自己的代码!
此引导过程的结果是为生成 Swift 代码提供更强大且更符合人体工程学的 API。
以下示例展示了 Swift 的表达能力如何允许构建器闭包,该闭包与生成的源代码非常相似。对于以下 Swift 代码片段
struct Point {
let x: Int
let y: Int
}
对应的 SwiftSyntaxBuilder
DSL 将是
StructDecl(identifier: "Point") {
VariableDecl(.let, name: "x", type: "Int")
VariableDecl(.let, name: "y", type: "Int")
}
有关更多信息,请查看该项目的文档。
改进类型推断算法的调试输出
Swift 的类型推断算法是 Swift 开发者体验的核心。该算法使我们能够编写源代码,而无需始终向编译器提供显式的类型信息。
该算法通过基于约束的类型检查器实现,该检查器从源代码收集可用的类型上下文,并尝试为源代码中缺少类型信息的部分求解具体类型,从而生成有效的、完全类型化的 Swift 表达式。
类型推断算法生成用于调试的输出,这在处理无效表达式时尤其有用。但是,此输出一直难以理解且笨拙
$T0 [lvalue allowed] [noescape allowed] delayed bindings={} @ locator@0x1258ee200 [OverloadedDeclRef@/…]
$T1 [noescape allowed] delayed literal=3 bindings={} @ locator@0x1258f0ac0 [IntegerLiteral@/…]
$T2 [noescape allowed] delayed literal=3 bindings={} @ locator@0x1258f0b78 [StringLiteral@/…]
$T3 [noescape allowed] delayed bindings={} @ locator@0x1258f0c40 [Binary@/… -> function result]
此输出具有重复元素,看起来不连贯,并且不显示重要的类型和过程详细信息。
在过去几个月中,调试输出经过了重新设计和重新格式化,以提高其可读性。为了更容易理解表达式或子表达式是如何进行类型检查的,输出现在通过显示约束简化和求解器范围更改来密切跟踪约束求解器步骤。输出还显式声明上下文中的重要类型信息,以显示约束求解器的路径如何更改类型变量绑定和关系。此外,重新设计的布局将类型属性、简化过程和嵌套的约束求解器范围组合在一起,以获得更友好的视觉格式
$T0 [allows bindings to: lvalue, noescape] [attributes: delayed] [with possible bindings: <empty>]) @ locator@0x13ca3e400 [OverloadedDeclRef@/…]
$T1 [allows bindings to: noescape] ($T1 [attributes: delayed, [literal: integer]] [with possible bindings: (default type of literal) Int]) @ locator@0x13ca3f398 [IntegerLiteral@/…]
$T2 [allows bindings to: noescape] [attributes: delayed, [literal: string]] [with possible bindings: (default type of literal) String]) @ locator@0x13ca42e68 [StringLiteral@/…]
$T3 [allows bindings to: noescape] [attributes: delayed] [with possible bindings: <empty>]) @ locator@0x13ca42f30 [Binary@/… -> function result]
查看 Amritpan 的论坛帖子以获取更多信息。
ArgumentParser 的交互模式
swift-argument-parser 提供了一种在 Swift 中创建高质量、用户友好的命令行工具的快速简便的方法。
即将推出的交互模式可以提示缺少输入,以帮助引导用户使用不熟悉的命令行工具。交互模式延续了 ArgumentParser 提供轻量级编码体验的方法,并建立在工具作者已提供的元数据之上。
$ roll --help
USAGE: roll --times <n> --sides <m> [--verbose]
OPTIONS:
--times <n> Rolls the dice <n> times.
--sides <m> Rolls an <m>-sided dice.
-v, --verbose Show all roll results.
-h, --help Show help information.
$ roll --verbose --times 3
? Please enter 'sides': 6
Roll 1: 1
Roll 2: 6
Roll 3: 3
Total: 10
交互模式将包含在 ArgumentParser 未来的版本中,但您现在可以在 feature/interactive
分支上试用它。
Swift-DocC 网站中的快速导航
作者:Sofía Rodríguez
导师:Marina Aísa, Franklin Schrans, Beatriz Magalhaes
此功能创建了一种快速且易于访问的方式,用于在 Swift-DocC 文档网站中导航和发现符号,类似于 Xcode 中的“快速打开”。
主要功能
- 模糊搜索 - 通过搜索词的模糊匹配查找符号名称。
- 符号排名 - 结果经过排序,因此最相关的结果位于顶部。这是通过使用相似性指标来完成的,例如输入和匹配之间的长度差异、符号名称的长度以及匹配在字符串中发生的距离起点的距离。
- 键盘导航 - 此功能可通过键盘快捷键完全访问,即使导航侧边栏折叠,也可以轻松执行查询。
查看 Sofía 的论坛帖子以获取更多信息。
Swift 的 Kafka 客户端软件包
SwiftKafka 是一个新的 Swift 软件包,它提供了一种与 Apache Kafka 服务器通信的便捷方式。在软件包开发过程中,主要目标是创建一个利用 Swift 新的并发特性的 API。在底层,此软件包使用 librdkafka C 库,将不安全且阻塞的 API 包装到更安全、更符合人体工程学的 Swift API 中。
以下示例展示了如何使用新的软件包来生成和消费来自 Kafka 服务器的消息
生产者 API
KafkaProducer
的 sendAsync(_:)
方法返回一个 message-id
,可用于标识相应的确认。确认通过 acknowledgements
AsyncSequence
接收。每个确认都指示消息的生成是成功还是返回错误。
let producer = try await KafkaProducer(
config: .init(),
logger: logger
)
let messageID = try await producer.sendAsync(
KafkaProducerMessage(topic: "topic-name", value: "Hello, World!")
)
for await acknowledgement in producer.acknowledgements {
/// ...
}
消费者 API
使用主题-分区对初始化 KafkaConsumer
后,可以使用 messages
AsyncSequence
消费消息。
let consumer = try KafkaConsumer(
topic: "topic-name",
partition: KafkaPartition(rawValue: 0),
config: .init(),
logger: logger
)
for await messageResult in consumer.messages {
// ...
}
总结
有关更多信息以及往年的项目,请查看