Требования к включению
Стандартная библиотека 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)
Включение на уровне модуля
Если вы не хотите аннотировать каждое использование 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.
© 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