6月,苹果公司推出了Swift System,这是一个适用于苹果平台的新库,为系统调用和低级货币类型提供习惯性接口。今天,我很高兴地宣布,我们正在开源System,并增加了对Linux的支持!我们的愿景是让System最终成为所有支持的Swift平台的低级系统接口的单一家园。我们的愿景是让System最终成为所有支持的Swift平台的低级系统接口的单一家园。
告别进口的 C 语言接口
今天的大多数操作系统都支持某种用C语言编写的系统接口,这些接口已经存在了几十年。虽然可以直接从 Swift 中使用这些 API,但这些从 C 语言导入的弱类型系统接口可能容易出错且不方便。例如,open 系统调用(可用于类似 UNIX 的操作系统,如 Linux 和苹果平台)以一对全局函数的形式导入:
func open(_ path: UnsafePointer<CChar>, _ oflag: Int32) -> Int32
func open(_ path: UnsafePointer<CChar>, _ oflag: Int32, _ mode: mode_t) -> Int32
这些弱类型的函数有几个缺点,不能利用Swift的表现力和类型安全:
-
文件描述符,以及选项、命令、errno和其他值,被作为普通的
Int32s导入。 -
oflag参数实际上是对一个文件访问模式和任意数量的标志的逻辑 OR-ing,但这并没有在oflag的类型中体现出来。 -
open的调用者必须记住检查是否有表示错误的负返回值,如果有,则检查全局变量errno的值,以了解发生了什么错误。此外,如果发生了信号,一些系统调用可能会被取消,这就要求调用者记得在这些调用周围写一个循环,检查是否有EINTR错误。 -
文件路径是非管理的指针,如果它们是从管理对象派生出来的(例如
Array<CChar>),那么调用者必须确保该数组总是空尾的。
这些语义规则都没有在API的签名中得到体现,这使得编程语言无法指导用户正确使用API。
Hello Idiomatic Swift Interfaces
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类型进行转换也很容易。 -
错误是用标准的语言机制抛出的,不会被错过。 此外,所有可由信号中断的系统调用都有一个默认的真参数
retryOnInterrupt,导致它们在失败时重试。 这两个变化结合起来,极大地简化了错误和信号处理。 -
FilePath是一个符合 的、有管理的、空尾的字节包--比 更安全。ExpressibleByStringLiteralUnsafePointer<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包管理器。System ,并不消除对#if os() 条件式实现跨平台抽象的需要,但它确实使填写平台特定的部分更加安全和更具表现力。
下一步是什么?
系统只是处于起步阶段--它目前包括少量的系统调用、货币类型和便利功能。作为增加 API 覆盖面的努力的一部分,我们将努力在 Swift 包管理器中采用 System。这将包括对 FilePath 的增强,以及增加对最近宣布的Swift on Windows 的支持。
还有一大堆令人兴奋的工作要做。系统(尤其是即将到来的Windows支持!)是一个参与Swift项目的绝佳机会,可以帮助它成长为一个强大、充满活力的跨平台生态系统。