3.1.2 用特性提供可配置的包
4 分钟阅读
原文链接: https://docs.swift.org/latest/documentation/packagemanagerdocs/packagetraits/
3.1.2 用特性提供可配置的包
定义一个或多个包特性,为包提供默认功能和可配置功能。
概述
在 6.1 版本之前,Swift 包对每个版本提供的都是一套不可配置的 API。从 Swift 6.1 开始,包可以提供特性(trait),用来表达该包的一套可配置 API。
用特性在包的核心 API 之外启用额外的 API。例如,某个特性可以启用实验性 API、需要额外依赖的可选扩展功能,或者你只希望在特定情况下启用的功能。
你在构建某个包时指定的特性,只在该包内部生效。如果你的包想使用某个依赖包中的特性,就需要在依赖中写明它所需要的特性。
注意:启用某个特性时,不要移除或禁用公共 API。
在定义特性的包内部,该特性表达了条件编译。Swift Package Manager 会把已启用的特性作为条件编译块(例如 #if YourTrait)暴露出来,你可以用它们有条件地启用导入,或在代码中选择不同的编译路径。
特性名称在承载它们的包内是有命名空间的。一个包中的特性名称不会影响任何其他包。特性名称必须是有效的 Swift 标识符,此外还可以包含 - 和 + 这两个字符。不要使用特性名 default 或 defaults(无论大小写)。不允许这些名称,是为了避免与包定义的默认特性混淆。
声明特性
创建一个特性来定义额外的功能,并在包清单的 traits 属性中定义它。使用 .default(enabledTraits:) 提供该包默认使用的那组特性。如果你没有定义默认启用的特性集合,Swift Package Manager 默认不启用任何特性。
下面的例子展示了一个默认启用的单一特性 FeatureA:
| |
特性也可以代表一组其他特性,这让你能够把功能分组。下面的例子定义了三个特性,以及一个额外的特性(B-and-C),它会同时启用特性 FeatureB 和 FeatureC:
| |
对于上面的例子,默认特性是 FeatureA。
注意:如果修改包的默认特性集合会移除 API,那就是一次主版本语义变更。 增加特性不是主版本变更。
Swift Package Manager 把特性视为纯粹可叠加的,并会在整个构建图中的所有包之间统一已启用的特性。请这样设计你的特性:它们启用的是额外的 API(以及必要时的相应依赖)。
定义互斥的特性
包清单格式不支持声明互斥的特性。在少数确实需要提供互斥特性的情况下,请在代码中保护这种场景:
| |
注意:提供互斥特性可能导致开发者在同时启用它们时出现编译错误。
依赖带特性的包
未指定特性的包依赖,会以该包的默认特性启用的方式使用它。要启用特定特性,请把它们加入包依赖声明中的 traits 参数。
下面的例子展示如何依赖 swift-configuration,并同时启用 defaults 和 YAML 两个特性:
| |
提示:当你为某个依赖指定特性时,你显式定义了要启用哪些特性。 默认特性不会被自动包含进来。 如果要同时使用默认特性和额外特性,请在指定的特性列表中加上
.defaults。
在代码中使用特性
把特性的名称用于条件编译。把该特性对应的额外 API 包在条件编译块里。例如,如果定义了特性 FeatureA 并且它处于启用状态,编译器就会看到并编译函数 additionalAPI():
| |
用特性启用条件依赖
你可以用特性来可选地引入某个依赖,或者引入启用了特定特性的依赖,以支撑你通过该特性公开的功能。为此,先把需要的依赖加入清单的 dependencies 声明,然后为包中定义的某个或某些特性使用条件依赖,把该依赖添加到某个目标上。
下面的例子展示了一个包清单的相关部分,它定义了特性 FeatureB,以及一个仅在该特性启用时才使用的本地依赖:
| |
下面的代码把导入包在特性的条件编译中,并定义了使用该依赖的额外 API:
| |