Spec-Zone.ru › Kotlin 1.7

Требования к включению

Стандартная библиотека Kotlin предоставляет механизм для требования и предоставления явного согласия на использование определенных элементов API. Этот механизм позволяет разработчикам библиотек информировать пользователей своих API о конкретных условиях, требующих включения, например, если API находится в экспериментальном состоянии и, вероятно, изменится в будущем.

Для предотвращения потенциальных проблем компилятор предупреждает пользователей о таких API об этих условиях и требует их включения перед использованием API.

Включение использования API

Если автор библиотеки помечает объявление из API библиотеки как требующее включение, вы должны дать явное согласие на его использование в своем коде. Существует несколько способов включить такие API, все они применимы без технических ограничений. Вы можете выбрать тот способ, который вам больше подходит.

Распространение включения

Когда вы используете API в коде, предназначенном для использования третьими сторонами (библиотека), вы можете распространить его требование к включению и на свой API. Для этого добавьте к своему объявлению аннотацию требования к включению используемого API в его теле. Это позволит вам использовать элементы API, которые требуют включения.

// Library code
@RequiresOptIn(message = "This API is experimental. It may be changed in the future without notice.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class MyDateTime // Opt-in requirement annotation

@MyDateTime                            
class DateProvider // A class requiring opt-in
// Client code
fun getYear(): Int {  
    val dateProvider: DateProvider // Error: DateProvider requires opt-in
    // ...
}

@MyDateTime
fun getDate(): Date {  
    val dateProvider: DateProvider // OK: the function requires opt-in as well
    // ...
}

fun displayDate() {
    println(getDate()) // Error: getDate() requires opt-in
}

Как вы можете видеть в этом примере, аннотированная функция, похоже, является частью @MyDateTime API. Таким образом, такое включение распространяет требование к включению на клиентский код; его клиенты увидят то же сообщение об ошибке и будут обязаны дать согласие.

Неявные использования API, которые требуют включения, также требуют включения. Если элемент API не имеет аннотации требования к включению, но его сигнатура включает тип, объявленный как требующий включения, его использование все равно вызовет предупреждение. См. пример ниже.

// Client code
fun getDate(dateProvider: DateProvider): Date { // Error: DateProvider requires opt-in
    // ...
}

fun displayDate() {
    println(getDate()) // Warning: the signature of getDate() contains DateProvider, which requires opt-in
}

Чтобы использовать несколько API, которые требуют включения, пометьте объявление всеми их аннотациями требования к включению.

Нераспространяемое включение

В модулях, которые не предоставляют свой собственный API, таких как приложения, вы можете включить использование API без распространения требования к включению на ваш код. В этом случае отметьте ваше объявление с помощью @OptIn, передав аннотацию требования к включению в качестве аргумента:

// Library code
@RequiresOptIn(message = "This API is experimental. It may be changed in the future without notice.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class MyDateTime // Opt-in requirement annotation

@MyDateTime                            
class DateProvider // A class requiring opt-in
// Client code
@OptIn(MyDateTime::class)
fun getDate(): Date { // Uses DateProvider; doesn't propagate the opt-in requirement
    val dateProvider: DateProvider
    // ...
}

fun displayDate() {
    println(getDate()) // OK: opt-in is not required
}

Когда кто-то вызывает функцию getDate(), они не будут проинформированы о требованиях к включению API, используемых в ее теле.

Обратите внимание, что если @OptIn применяется к объявлению, сигнатура которого содержит тип, объявленный как требующий включения, включение все равно будет распространяться:

// Client code
@OptIn(MyDateTime::class)
fun getDate(dateProvider: DateProvider): Date { // Has DateProvider as a part of a signature; propagates the opt-in requirement
    // ...
}

fun displayDate() {
    println(getDate()) // Warning: getDate() requires opt-in
}

Чтобы использовать API, требующий включения, во всех функциях и классах в файле, добавьте аннотацию уровня файла @file:OptIn в начало файла перед спецификацией пакета и импортами.

// Client code
@file:OptIn(MyDateTime::class)

Включение на уровне модуля

Опция компилятора -opt-in доступна начиная с Kotlin 1.6.0. Для более ранних версий Kotlin используйте -Xopt-in.

Если вы не хотите аннотировать каждое использование API, требующего включения, вы можете включить их для всего своего модуля. Чтобы включить использование API в модуле, скомпилируйте его с аргументом -opt-in, указав полное имя аннотации требования к включению используемого API: -opt-in=org.mylibrary.OptInAnnotation. Компиляция с этим аргументом имеет тот же эффект, что и если у каждого объявления в модуле была бы аннотация @OptIn(OptInAnnotation::class).

Если вы строите свой модуль с помощью Gradle, вы можете добавить такие аргументы:

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
    kotlinOptions.freeCompilerArgs += "-opt-in=org.mylibrary.OptInAnnotation"
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
    kotlinOptions {
        freeCompilerArgs += "-opt-in=org.mylibrary.OptInAnnotation"
    }
}

Если ваш модуль Gradle является модулем многоплатформенным, используйте метод optIn:

sourceSets {
    all {
        languageSettings.optIn("org.mylibrary.OptInAnnotation")
    }
}
sourceSets {
    all {
        languageSettings {
            optIn('org.mylibrary.OptInAnnotation')
        }
    }
}

Для Maven это было бы:

<build>
    <plugins>
        <plugin>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-plugin</artifactId>
            <version>${kotlin.version}</version>
            <executions>...</executions>
            <configuration>
                <args>
                    <arg>-opt-in=org.mylibrary.OptInAnnotation</arg>                    
                </args>
            </configuration>
        </plugin>
    </plugins>
</build>

Чтобы включить несколько API на уровне модуля, добавьте один из описанных аргументов для каждой метки требования к включению, используемой в вашем модуле.

Требование включения для API

Создание аннотаций требований к включению

Если вы хотите потребовать явного согласия на использование API вашего модуля, создайте класс аннотаций, который будет использоваться в качестве аннотации требования к включению. Этот класс должен быть аннотирован с помощью @RequiresOptIn:

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

Аннотации требований к включению должны соответствовать нескольким требованиям:

  • BINARY или RUNTIME удержание

  • Без EXPRESSION, FILE, TYPE, или TYPE_PARAMETER среди мишеней

  • Без параметров.

Требование включения может иметь один из двух уровней серьезности уровней:

  • RequiresOptIn.Level.ERROR. Включение является обязательным. В противном случае код, использующий отмеченный API, не будет компилироваться. Уровень по умолчанию.

  • RequiresOptIn.Level.WARNING. Включение не является обязательным, но рекомендуется. Без него компилятор выдает предупреждение.

Для установки желаемого уровня укажите параметр level аннотации @RequiresOptIn.

Кроме того, вы можете предоставить message для информирования пользователей API об особых условиях использования API. Компилятор отобразит его пользователям, которые используют API без включения.

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

Если вы публикуете несколько независимых функций, которые требуют включения, объявляйте аннотацию для каждой. Это делает использование API безопаснее для ваших клиентов: они могут использовать только те функции, которые они явно принимают. Это также позволяет вам удалять требования к включению из функций независимо.

Помечать элементы API

Чтобы потребовать включения для использования элемента API, аннотируйте его объявление аннотацией требования к включению:

@MyDateTime
class DateProvider

@MyDateTime
fun getTime(): Time {}

Обратите внимание, что для некоторых языковых элементов аннотация требования к включению неприменима:

  • Вы не можете аннотировать вспомогательное поле или геттер свойства, только само свойство.

  • Вы не можете аннотировать локальную переменную или параметр значения.

Требования к включению для предварительно стабильных API

Если вы используете требования к включению для функций, которые еще не стабильны, тщательно обрабатывайте переход API к стабильному состоянию, чтобы избежать разрыва кода клиента.

После того, как ваш предварительно стабильный API созреет и будет выпущен в стабильном состоянии, удалите аннотации требования к включению из объявлений. Клиенты смогут использовать их без ограничений. Однако вы должны оставить классы аннотаций в модулях, чтобы код существующих клиентов оставался совместимым.

Чтобы позволить пользователям API обновить свои модули соответственно (удалить аннотации из своего кода и перекомпилировать), отметьте аннотации как @Deprecated и предоставьте объяснение в сообщении об устаревании.

@Deprecated("This opt-in requirement is not used anymore. Remove its usages from your code.")
@RequiresOptIn
annotation class ExperimentalDateTime
Последнее изменение: 20 сентября 2022 г.
Функции области действия Руководство по сопрограммам

© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/opt-in-requirements.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API