Spec-Zone.ru › Kotlin 1.6

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

Аннотации требований к включению @RequiresOptIn и @OptIn находятся в стадии Бета. Функциональность почти стабильна, но в будущем могут потребоваться действия по миграции. Мы постараемся свести к минимуму изменения, которые вам придётся внести. Подробнее см. раздел Статус бета-версии требований к включению.

Стандартная библиотека 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 {}

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

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

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

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

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

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

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

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

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

Статус бета-версии требований к включению

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

Чтобы пользователи аннотаций @OptIn и @RequiresOptIn были осведомлены о их предварительно стабильном статусе, компилятор выводит предупреждения при компиляции кода с этими аннотациями:

This annotation should be used with the compiler argument '-opt-in=kotlin.RequiresOptIn'

Чтобы устранить предупреждения, добавьте аргумент компилятора -opt-in=kotlin.RequiresOptIn.

Узнайте больше о последних изменениях в требованиях к включению в этом KEEP.

Последнее изменение: 07 апреля 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