Swift系统现在是开源的

227 阅读4分钟

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 模块带来了各种语言特性,以提高表达能力并消除这些错误的机会。 例如,Systemopen 系统调用定义为静态函数,并在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 是一个符合 的、有管理的、空尾的字节包--比 更安全。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

我们的直接目标是简化跨平台库和应用程序的构建,如SwiftNIOSwift包管理器System ,并不消除对#if os() 条件式实现跨平台抽象的需要,但它确实使填写平台特定的部分更加安全和更具表现力。

下一步是什么?

系统只是处于起步阶段--它目前包括少量的系统调用、货币类型和便利功能。作为增加 API 覆盖面的努力的一部分,我们将努力在 Swift 包管理器中采用 System。这将包括对 FilePath 的增强,以及增加对最近宣布的Swift on Windows 的支持。

还有一大堆令人兴奋的工作要做。系统(尤其是即将到来的Windows支持!)是一个参与Swift项目的绝佳机会,可以帮助它成长为一个强大、充满活力的跨平台生态系统。