为什么我可以将 Codable 与 Swift 3.3 的项目语言版本一起使用?

Why can I use Codable with a project language version of Swift 3.3?

Codable 在 Swift 4 中被引入。我的项目语言版本是 Swift 3.3,但我仍然可以在我的项目中使用 Codable。这不是问题,但这怎么可能呢?我只想知道。

我想你可能使用的是最新的 Swift 编译器。

Swift 编译器版本和"Swift Language Version" 构建设置(对应于
-swift-version 命令行标志)是两个不同的东西。前者是您正在使用的 实际 版本的编译器和标准库,而后者只是一个标志,告诉编译器尝试模仿之前 Swift 的行为版本。这允许更流畅的迁移体验——您可以更新到最新的 Swift 编译器,而无需立即更新您的代码库以适应语言的最新变化。

在您的情况下,听起来您使用的是 Swift 4.1 编译器,"Swift Language Version" 设置为 Swift 3.3。这被称为 "Swift 3 compatibility mode"。请注意,版本 Swift 3.3 是伪版本 - 它的存在仅代表 Swift 4.1 编译器 运行 在 Swift 3 兼容模式下。

这是一个方便的 table(信息取自 SE-0212),它根据兼容模式将编译器映射到语言版本:

(请注意,现在 SE-0212 已实施,此兼容模式的版本升级将不再适用于 Swift 5 及更高版本)

所以这意味着您正在使用 Swift 4.1 标准库(其中包括新的 Codable 协议)并使用 Swift 4.1 编译器(其中包括必要的Codable 综合的编译器魔法)。这就是为什么您仍然可以利用新的 Codable 协议。

然而,通过 运行 在 Swift 3 兼容模式下,您指示编译器模仿 Swift 3 编译器的行为。例如,这将导致它允许您访问标记为 @available(swift, obsoleted: 4) 的声明,阻止您访问标记为 @available(swift, introduced: 4) 的声明,忽略 #if swift(>=4) 条件编译块中的代码,否则执行其最好保持与 Swift 3.

的源兼容性

后者并不总能完美实现,例如使用 Swift 3.1 编译器编译:

protocol P {}
typealias X = protocol<P, AnyObject>
class C : X {}

但它无法在 Swift 3 兼容模式 (SR-8153) 中使用 Swift 4.1 编译器 运行 进行编译。

如果 DecodableEncodable 协议被标记为 @available(swift, introduced: 4),那么您确实无法在 Swift 3 兼容模式下访问它们。但是没有真正的理由这样标记它们,因为没有真正的理由阻止人们在 Swift 3 模式下利用它们,因为 Swift 4 编译器完全支持它们。

然而,由于 Swift3 兼容模式只是一种源代码兼容性的临时模式,因此您无法在未来的编译器版本中永远使用它。它 will no longer be an option in the Swift 5 compiler(但是,您将拥有 Swift 4 的兼容模式)。因此,您需要确保在某个时候将代码库更新为 Swift 4,以便能够顺利迁移到 Swift 5 编译器。

最后,值得注意的是新的 compiler 指令(可用于条件编译块)is being introduced in Swift 4.2。与 #if swift(...) 检查由 -swift-version 提供的语言版本不同,#if compiler(...) 将检查编译器的实际版本,忽略它可能在 运行 中的任何兼容模式。