使用即将推出的功能标志
从 Swift 5.8 开始,您可以使用新的编译器标志和编译条件灵活地采用即将推出的 Swift 功能。这篇文章描述了即将推出的功能标志所解决的问题、它们的优势,以及如何在您的项目中开始使用它们。
破坏源代码的更改
Swift 的每个新版本都会添加功能和特性。这些更改都经过 Swift 演进流程,在该流程中,它们被提出、由社区讨论并被接受。
对于 Swift 的所有更改,一个重要的考虑因素是源代码兼容性。为了保持源代码兼容性,现有的 Swift 代码必须在新版本的编译器下继续编译并按预期运行。
为了帮助实现这个强大的目标,Swift 项目维护了一个广泛的源代码兼容性测试套件。对提议的更改进行测试,以确保它们不会引入破坏源代码的更改。此外,每个演进提案都包含对源代码兼容性的讨论。
在极少数情况下,会认为破坏源代码兼容性的提议更改足够重要而被接受。这些破坏源代码的更改不会立即引入,而是等到 Swift 的下一个主要版本。
示例:正则表达式字面量
Swift 5.7 中引入的正则表达式字面量语法是破坏源代码更改的一个例子。
所需的字面量语法是将正则表达式模式括在正斜杠中,这在许多不同的工具和语言中是正则表达式的约定
let regex = /[a-zA-Z_][0-9a-zA-Z_]*/
然而,在某些情况下,这种新语法会破坏现有代码,如 SE-0354 提案 中详述的那样。
即使源代码不兼容性不会影响许多项目,并且在受影响的项目中不太可能难以修复,但它仍然是一个破坏性更改。
因此,在 Swift 5.7 中,正则表达式字面量仅支持扩展的字面量分隔符
let regex = #/[a-zA-Z_][0-9a-zA-Z_]*/#
破坏源代码的更改要到下一个主要语言版本 Swift 6 才会生效。
然而,开发者现在能够选择使用正则表达式字面量的“裸斜杠”语法,而不是等到 Swift 6,这将是有益的。
为了允许这样做,在引入 Swift 5.7 时,添加了一个新的编译器标志 -enable-bare-slash-regex
。对于任何设置了此标志的目标,Swift 6 语法都会被接受。
随 Xcode 14 一起发布的 SDK 默认设置了此标志,因此您可能已经在使用了此语法。
通用的解决方案
能够尽早而不是稍后采用即将到来的更改是一个好主意。但是,为每个即将推出的功能添加越来越多的单独的编译器标志并不能很好地扩展。
为了解决这个问题,Swift 演进提案 SE-0362(在 Swift 5.8 中实现)详细介绍了一种用于启用即将推出的功能的通用机制。
编译器不是为每个即将推出的功能创建不同的编译器标志,而是获得一个新标志,后跟要启用的功能的名称
-enable-upcoming-feature SomeUpcomingFeature
例如,要启用即将推出的正则表达式字面量语法,您将使用
-enable-upcoming-feature BareRegexLiteralSyntax
在 Swift Package Manager 清单中,您可以使用新的 SwiftSetting
来指定这些
.enableUpcomingFeature("BareSlashRegexLiterals")
在代码中检查功能
SE-0362 还引入了一个新的 hasFeature()
编译条件,用于检查是否启用了某个功能。这允许您编写代码,在功能存在时使用该功能,否则使用备用代码。
您可以通过使用其即将推出的功能标志作为 hasFeature()
的参数来指定要检查的功能,如下例所示。
请注意,由于 hasFeature()
是随 Swift 5.8 编译器一起引入的,因此早期版本无法识别它。使用它时,您可能需要检查编译器版本。
例如
#if compiler(>=5.8)
#if hasFeature(BareSlashRegexLiterals)
let regex = /.../
#else
let regex = #/.../#
#endif
#else
let regex = try NSRegularExpression(pattern: "...")
#endif
SE-0362 的 源代码中的功能检测 部分详细讨论了 hasFeature()
的使用。
启用即将推出的功能的好处
在您的代码中启用即将推出的功能有两个显著的好处。
首先,您会立即发现您的代码是否需要更改。这使您可以了解所需工作的范围,并让您可以灵活地立即更新代码,或在最适合您的时间更新。
其次,您可以立即开始使用即将推出的功能。您编写的所有新代码都将包含这些更改,从而简化您最终迁移到下一个主要语言版本的过程。您还将开始建立“肌肉记忆”,并获得即将推出的语法和行为的经验。
如何启用即将推出的功能
您可以通过为给定目标设置编译器标志来启用即将推出的功能。
要启用多个功能,请多次使用编译器标志,每个启用的功能一次。
这使您可以非常灵活地按目标、按功能采用功能。
在 Xcode 中
对于 Xcode 项目,将编译器标志添加到“Other Swift Flags”构建设置中
- 在项目导航器中,选择项目
- 在项目编辑器中,选择所需的目标或项目本身
- 选择“Build Settings”选项卡
- 确保选中“All”范围按钮
- 搜索“swift flags”以查找“Other Swift Flags”构建设置
- 双击以将一个或多个
-enable-upcoming-feature
标志添加到设置中
下面的屏幕截图显示了三个即将推出的功能已启用
如果您的项目使用 xcconfig
配置文件,您可以使用反斜杠使构建设置跨越多行,从而提高多个设置的可读性
OTHER_SWIFT_FLAGS = $(inherited) \
-enable-upcoming-feature ConciseMagicFile \
-enable-upcoming-feature BareSlashRegexLiterals \
-enable-upcoming-feature ExistentialAny
在 SwiftPM 包中
对于 Swift 包,在其包清单的 SwiftSetting
数组中为目标启用即将推出的功能
.target(name: "MyTarget",
dependencies:[.fancyLibrary],
swiftSettings:
[.enableUpcomingFeature("ConciseMagicFile"),
.enableUpcomingFeature("BareSlashRegexLiterals"),
.enableUpcomingFeature("ExistentialAny")])
您还需要将清单中指定的工具版本更新为 5.8 或更高版本
// swift-tools-version: 5.8
查找即将推出的功能标志
使用 Swift 演进仪表板 查找即将推出的功能标志
- 筛选以查看所有带有即将推出的功能标志的提案
- 按名称搜索即将推出的功能标志
- 查看定义了即将推出的功能标志的提案的标志
每个仪表板条目都链接到完整的 Swift 演进提案,其中定义了即将推出的功能标志。有关标志启用的更改的详细信息在提案的正文中,通常在源代码兼容性部分。
同样重要的是要注意,Swift 的大多数更改都保持了源代码兼容性,因此没有即将推出的功能标志。
Swift 5.8 中添加的即将推出的功能标志
截至 Swift 5.8,当前即将推出的功能标志集如下
SE-0274:简洁的魔法文件名
#file
字面量生成一个格式为 <module-name>/<file-name>
的字符串,而不是完整的文件路径。
即将推出的功能标志:ConciseMagicFile
SE-0286:尾随闭包的前向扫描匹配
当使用多个尾随闭包调用时,一些现有方法可能会模棱两可或无法进行类型检查。在这些情况下,请将闭包作为常规参数提供。
即将推出的功能标志:ForwardTrailingClosures
SE-0335:引入存在类型 any
当协议用作存在类型时,必须使用 any
关键字。
示例
@protocol Drawable { }
let drawable: any Drawable // Use of 'any' keyword required
即将推出的功能标志:ExistentialAny
SE-0354:正则表达式字面量
允许正则表达式字面量使用正斜杠作为分隔符。
示例
let regex = /[a-zA-Z_][0-9a-zA-Z_]*/
即将推出的功能标志:BareSlashRegexLiterals
立即开始使用
启用即将推出的功能为您提供了一种灵活的方式,让您能够以自己的节奏,按功能、按目标迁移代码,以采用 Swift 下一个主要版本中的更改。
您可以通过创建项目的测试分支并一次启用一个即将推出的功能、一次启用一个目标,以低风险的方式立即开始研究这些功能。
当然,在一个团队中,这种代码迁移需要进行计划和沟通。
Swift 5.8 中的这些新功能为您和您的团队提供了额外的提前时间和灵活性,以便调查、计划和安排采用即将推出的功能所需的任何更改。