Python实战社群
Java实战社群
长按识别下方二维码,按需求添加
扫码关注添加客服
进Python社群▲
扫码关注添加客服
进Java社群▲
作者 | Michael Ilseman
来源 | swift.org
今年 6 月,Apple 推出了 Swift System,这是 Apple 平台的一个新库,它为系统调用和底层 currency 类型提供常用的接口。今天,我很高兴地宣布我们正式开源 System,并增加了 Linux 支持!我们的愿景是使 System 最终充当所有支持 Swift 平台的底级系统接口的唯一宿主。
导入 C 接口成为历史
如今,大多数操作系统都支持使用 C 语言编写的系统接口,这些接口已有数十年历史。尽管可以直接在 Swift 中使用这些 API,但是从 C 导入的这些类型较弱的系统接口可能容易出错且难以处理。例如,open 系统调用(可在类 UNIX 的操作系统上使用)作为一对全局函数导入:
func open(_ path: UnsafePointer<CChar>, _ oflag: Int32) -> Int32
func open(_ path: UnsafePointer<CChar>, _ oflag: Int32, _ mode: mode_t) -> Int32
这些弱类型函数有几个缺点,无法利用 Swift 的表现力和类型安全性:
文件描述符以及选项,命令,errno 和其他值是以 Int32 类型被导入;
oflag 参数实际上是一个文件访问模式和任意数量的标志的逻辑或运算,但不会以 oflag 类型捕获;
open 的调用者必须记住检查指示错误的负返回值,从而则检查全局变量 errno 的值以了解发生了什么错误。此外,如果出现某些信号,某些系统调用可能会被取消,要求调用者记住围绕此类调用编写循环以检查 EINTR 错误。
文件路径是非托管指针,并且如果它们是从托管对象(例如 Array
)派生的,则调用者必须确保数组始终以 null 终止。
API 的签名中没有捕获任何这些语义规则,从而阻碍了编程语言引导用户正确使用 API。
常用的 Swift 接口
System 模块带来了多种语言功能,以提高表达能力并消除出现错误的机会。例如,System 使用 FileDescriptor 命名空间中的默认参数将 open 系统调用定义为静态函数:
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
相比,使用起来更加安全。
结果是代码读起来像像常用的 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 和行为,紧密反映了底层 OS 接口。一次导入将引入特定于目标 OS 的平台接口。
我们的近期目标是简化跨平台库和应用程序的构建,例如 SwiftNIO 和 Swift Package Manager。系统并没有消除使用 #if os() 条件来实现跨平台抽象的需求,但是它确实使使用特定于平台的部分变得更加安全和富有表现力。
下一步
System 仅处于起步阶段,目前包括少量系统调用,currency 类型和便利功能。为了扩大 API 覆盖范围,我们将努力在 Swift Package Manager 中采用 System。这将包括FilePath的增强,并增加对 Windows 上 Swift 的支持。
还有大量令人兴奋的工作要做。System 是参与 Swift 项目并帮助其成长为强大,充满活力的跨平台生态系统的绝佳机会。
程序员专栏 扫码关注填加客服 长按识别下方二维码进群
近期精彩内容推荐:
在看点这里好文分享给更多人↓↓