Swift System 现已开源
今年六月,Apple 推出了 Swift System,这是一个用于 Apple 平台的新库,它为系统调用和底层并发类型提供了符合语言习惯的接口。今天,我很高兴地宣布,我们将开源 System 并增加 Linux 支持!我们的愿景是让 System 最终成为所有受支持 Swift 平台的底层系统接口的统一入口。
告别导入的 C 接口
如今,大多数操作系统都支持以 C 语言编写的某种系统接口,这些接口已经存在了几十年。虽然可以直接从 Swift 中使用这些 API,但这些从 C 语言导入的弱类型系统接口可能容易出错且笨拙。例如,open
系统调用(在类 UNIX 操作系统(如 Linux 和 Apple 平台)上可用)导入为一对全局函数
func open(_ path: UnsafePointer<CChar>, _ oflag: Int32) -> Int32
func open(_ path: UnsafePointer<CChar>, _ oflag: Int32, _ mode: mode_t) -> Int32
这些弱类型函数存在若干缺点,并且未能利用 Swift 的表达性和类型安全性
-
文件描述符以及选项、命令、
errno
和其他值都作为普通的Int32
导入。 -
oflag
参数实际上是逻辑 OR 运算,恰好是一个文件访问模式和任意数量的标志,但这并未在oflag
的类型中捕获。 -
open
的调用者必须记住检查指示错误的负返回值,如果出现错误,则检查全局变量errno
的值以了解发生了什么错误。此外,如果发生信号,某些系统调用可能会被取消,要求调用者记住在这些调用周围编写一个循环,检查EINTR
错误。 -
文件路径是未管理的指针,如果它们是从托管对象(例如
Array<CChar>
)派生的,则调用者必须确保该数组始终以 null 结尾。
这些语义规则均未在 API 的签名中捕获,从而阻止编程语言引导用户正确使用 API。
你好,符合语言习惯的 Swift 接口
System
模块引入了各种语言特性,以提高表达能力并消除这些错误机会。例如,System
将 open
系统调用定义为 FileDescriptor
命名空间中具有默认参数的静态函数
extension FileDescriptor {
/// Opens or creates a file for reading or writing.
///
/// - Parameters:
/// - path: The location of the file to open.
/// - mode: The read and write access to use.
/// - options: The behavior for opening the file.
/// - permissions: The file permissions to use for created files.
/// - retryOnInterrupt: Whether to retry the open operation
/// if it throws `Errno.interrupted`.
/// The default is `true`.
/// Pass `false` to try only once and throw an error upon interruption.
/// - Returns: A file descriptor for the open file
///
/// The corresponding C function is `open`.
public static func open(
_ path: FilePath,
_ mode: FileDescriptor.AccessMode,
options: FileDescriptor.OpenOptions = FileDescriptor.OpenOptions(),
permissions: FilePermissions? = nil,
retryOnInterrupt: Bool = true
) throws -> FileDescriptor
}
当人们将这个版本的 open
与 C 语言的原始版本进行比较时,会发现几个显着的差异
-
System
广泛使用原始可表示的结构体和选项集。这些强类型有助于在编译时捕获错误,并且可以轻松地与较弱的 C 类型相互转换。 -
错误使用标准语言机制抛出,不会被遗漏。此外,所有可被信号中断的系统调用都采用默认值为 true 的
retryOnInterrupt
参数,使其在失败时重试。当结合使用时,这两个更改显着简化了错误和信号处理。 -
FilePath
是一个托管的、以 null 结尾的字节集合,它符合ExpressibleByStringLiteral
——比UnsafePointer<CChar>
更安全易用。
结果是代码的读取和行为都类似于符合语言习惯的 Swift 代码。例如,以下代码从字符串字面量创建一个文件路径,并使用它打开并追加到日志文件
let message: String = "Hello, world!" + "\n"
let path: FilePath = "/tmp/log"
let fd = try FileDescriptor.open(
path, .writeOnly, options: [.append, .create], permissions: .ownerReadWrite)
try fd.closeAfter {
_ = try fd.writeAll(message.utf8)
}
一个多平台库
System
是一个多平台库,而不是一个跨平台库。它在每个受支持的平台上提供一组单独的 API 和行为,紧密反映了底层操作系统接口。单个 import
将引入特定于目标操作系统的本机平台接口。
我们眼前的目标是简化构建跨平台库和应用程序,例如 SwiftNIO 和 Swift Package Manager。System
并未消除使用 #if os()
条件语句来实现跨平台抽象的需要,但它确实使填充平台特定部分的代码更安全、更具表现力。
下一步是什么?
System 仍处于起步阶段——目前仅包含少量的系统调用、并发类型和便利功能。作为增加 API 覆盖范围工作的一部分,我们将努力在 Swift Package Manager 中采用 System。这将包括 FilePath 的增强功能 以及对最近宣布的 Windows 版 Swift 的支持。
还有大量令人兴奋的工作要做。System(尤其是即将推出的 Windows 支持!)是参与 Swift 项目并帮助其成长为强大、充满活力的跨平台生态系统的绝佳机会。
参与进来
我们非常欢迎您的经验、反馈和贡献!
-
首先尝试 GitHub 上的 System 软件包,
-
在 Swift System 论坛 中讨论该库并获得帮助,
-
提交 issue,指出您发现的问题或您对改进的想法,
-
一如既往,欢迎提交 pull request!