选择加入要求

要求选择加入的注解 @RequiresOptIn@OptIn实验性的。 请参阅以下用法详细信息。

1.3.70 中引入了 @RequireOptIn@OptIn 注解以取代先前使用的 @Experimental@UseExperimental; 同时 -Xopt-in 编译器选项也取代了 -Xuse-experimental

Kotlin 标准库提供了一种机制,用于要求并明确同意使用 API 的某些元素。 通过这种机制,库开发人员可以将使用其 API 需要选择加入的特定条件告知用户, 例如,如果某个 API 处于实验状态,并且将来可能会更改。

为了避免潜在的问题,编译器会向此类 API 的用户发出警告, 告知他们这些条件,并要求他们在使用 API 之前选择加入。

选择使用 API

如果库作者将一个库的 API 声明标记为要求选择加入 你应该明确同意在代码中使用它。 有多种方式可以选择加入使用此类 API,所有方法均不受技术限制。 你可以自由选择最适合自己的方式。

传播选择加入

在使用供第三方(库)使用的 API 时,你也可以把其选择加入的要求传播到自己的 API。 为此,请在你的 API 主体声明中添加注解 要求选择加入的注解。 这可以让你使用带有此注解的 API 元素。

  1. // 库代码
  2. @RequiresOptIn(message = "This API is experimental. It may be changed in the future without notice.")
  3. @Retention(AnnotationRetention.BINARY)
  4. @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
  5. annotation class MyDateTime // 要求选择加入的注解
  6. @MyDateTime
  7. class DateProvider // 要求选择加入的类
  1. // 客户端代码
  2. fun getYear(): Int {
  3. val dateProvider: DateProvider // 错误:DateProvider 要求选择加入
  4. // ...
  5. }
  6. @MyDateTime
  7. fun getDate(): Date {
  8. val dateProvider: DateProvider // OK:该函数也需要选择加入
  9. // ...
  10. }
  11. fun displayDate() {
  12. println(getDate()) // 错误:getDate() 需要选择加入
  13. }

如本例所示,带注释的函数看起来是 @MyDateTime API 的一部分。 因此,这种选择加入会将选择加入的要求传播到客户端代码;其客户将看到相同的警告消息, 并且也必须同意。 要使用多个需要选择加入的API,请在声明中标记所有需要选择加入的注解。

非传播的用法

在不公开其自身API的模块(例如应用程序)中,你可以选择使用 API 而无需将选择加入的要求传播到代码中。 这种情况下,请使用 @OptIn 标记你的声明, 并以要求选择加入的注解作为参数:

  1. // 库代码
  2. @RequiresOptIn(message = "This API is experimental. It may be changed in the future without notice.")
  3. @Retention(AnnotationRetention.BINARY)
  4. @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
  5. annotation class MyDateTime // 要求选择加入的注解
  6. @MyDateTime
  7. class DateProvider // 要求选择加入的类
  1. //客户端代码
  2. @OptIn(MyDateTime::class)
  3. fun getDate(): Date { // 使用 DateProvider;不传播选择加入的要求
  4. val dateProvider: DateProvider
  5. // ...
  6. }
  7. fun displayDate() {
  8. println(getDate()) // OK:不要求选择加入
  9. }

当有人调用函数 getDate() 时,不会通知他们函数主体中使用的选择加入 API 的要求。

要在一个文件的所有函数和类中使用要求选择加入的 API,请在文件的顶部, 文件包说明和导入声明前添加文件级注释 @file:OptIn

  1. //客户端代码
  2. @file:OptIn(MyDateTime::class)

模块范围的选择加入

如果你不想在使用要求选择加入 API 的每个地方都添加注解,则可以为整个模块选择加入这些 API。 要选择在模块中使用 API,请使用参数 -Xopt-in 进行编译, 使用 -Xopt-in = org.mylibrary.OptInAnnotation 指定该 API 使用的要求选择加入注解的标准名称。 使用此参数进行编译的效果与模块中每个声明都有注解 @OptIn(OptInAnnotation::class) 的效果相同。

如果使用 Gradle 构建模块,可以添加如下参数:

  1. tasks.withType(KotlinCompile).configureEach {
  2. kotlinOptions {
  3. freeCompilerArgs += "-Xopt-in=org.mylibrary.OptInAnnotation"
  4. }
  5. }
  1. tasks.withType<KotlinCompile>().configureEach {
  2. kotlinOptions.freeCompilerArgs += "-Xopt-in=org.mylibrary.OptInAnnotation"
  3. }

如果你的 Gradle 模块是多平台模块,请使用 useExperimentalAnnotation 方法:

  1. sourceSets {
  2. all {
  3. languageSettings {
  4. useExperimentalAnnotation('org.mylibrary.OptInAnnotation')
  5. }
  6. }
  7. }
  1. sourceSets {
  2. all {
  3. languageSettings.useExperimentalAnnotation("org.mylibrary.OptInAnnotation")
  4. }
  5. }

对于 Maven,它将是:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.jetbrains.kotlin</groupId>
  5. <artifactId>kotlin-maven-plugin</artifactId>
  6. <version>${kotlin.version}</version>
  7. <executions>...</executions>
  8. <configuration>
  9. <args>
  10. <arg>-Xopt-in=org.mylibrary.OptInAnnotation</arg>
  11. </args>
  12. </configuration>
  13. </plugin>
  14. </plugins>
  15. </build>

要在模块级别选择加入多个 API,请为每个要求选择加入的 API 添加以上描述的参数之一。

要求选择加入 API

要求选择加入的注解

如果想获得使用者使用你的模块 API 的明确同意,请创建一个注解类,作为_要求选择加入的注解_。 这个类必须使用 @RequiresOptIn 注解:

  1. @RequiresOptIn
  2. @Retention(AnnotationRetention.BINARY)
  3. @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
  4. annotation class MyDateTime

要求选择加入的注解必须满足以下几个要求:

选择加入的要求可以具有以下两个严格级别之一:

  • RequiresOptIn.Level.ERROR。选择加入是强制性的。 否则,使用标记 API 的代码将无法编译。 默认级别。
  • RequiresOptIn.Level.WARNING。选择加入不是强制性的,而是建议使用的。 没有它,编译器会发出警告。

要设置所需的级别,请指定 @RequiresOptIn 注解的 level 参数。

另外,你可以提供一个 message 来通知用户有关使用该 API 的特定条件。 编译器会将其显示给使用该 API 但未选择加入的用户。

  1. @RequiresOptIn(level = RequiresOptIn.Level.WARNING, message = "This API is experimental. It can be incompatibly changed in the future.")
  2. @Retention(AnnotationRetention.BINARY)
  3. @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
  4. annotation class ExperimentalDateTime

如果你发布了多个需要选择加入的独立功能,请为每个功能声明一个注解。 这使你的用户可以更安全地使用 API:他们只能使用其明确接受的功能。 这也使你可以独立地从功能中删除选择加入的要求。

标记 API 元素

要在使用 API 时要求选择加入,请给它的声明添加要求选择加入的注解。

  1. @MyDateTime
  2. class DateProvider
  3. @MyDateTime
  4. fun getTime(): Time {}

稳定前 API 的选择加入要求

如果要求选择加入尚未稳定的特性,请仔细处理 API 由实验状态到稳定状态的转换, 以避免破坏客户端代码。

当稳定前 API 稳定之后并以稳定状态发布后,请从声明中删除其要求选择加入的注解。 客户端将可以不受限制地使用它们。但是,你应该将注解类留在模块中,以便与现有的客户端代码保持兼容。

为了让 API 用户相应地更新其模块(从代码中删除注解并重新编译), 请将注解标记为 @Deprecated 并在弃用 message 中提供说明。

  1. @Deprecated("This opt-in requirement is not used anymore. Remove its usages from your code.")
  2. @RequiresOptIn
  3. annotation class ExperimentalDateTime

选择加入要求的实验状态

选择加入要求的机制在 Kotlin 1.3 中是实验性的。 这意味着在将来的版本中,可能会以不兼容的方式进行更改。

为了让使用注解 @OptIn@RequiresOptIn 的用户了解其实验状态, 编译器会在编译代码时发出警告:

This class can only be used with the compiler argument '-Xopt-in=kotlin.RequiresOptIn'

要移除警告,请添加编译器参数 -Xopt-in=kotlin.RequiresOptIn