Spec-Zone.ru › Kotlin 2

Требования к явному согласию

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

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

Дать согласие на использование API

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

Дать согласие локально

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

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

@MyDateTime
// A class requiring opt-in
class DateProvider

В коде перед объявлением функции, использующей класс DateProvider, добавьте аннотацию @OptIn со ссылкой на класс аннотации MyDateTime:

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

// Uses DateProvider
fun getDate(): Date {
    val dateProvider: DateProvider
    // ...
}

Важно отметить, что при таком подходе, если функция getDate() вызывается в другом месте кода или используется другим разработчиком, явное согласие не требуется:

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

// Uses DateProvider
fun getDate(): Date {
    val dateProvider: DateProvider
    // ...
}

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

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

Распространение требований к явному согласию

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

Например, перед объявлением функции, использующей класс DateProvider, добавьте аннотацию @MyDateTime:

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

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

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

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

// Client code
@MyDateTime
fun getDate(dateProvider: DateProvider = DateProvider()): Date

@MyDateTime
fun displayDate() {
    // OK: the function requires opt-in as well
    println(getDate())
}

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

// Client code
@OptIn(MyDateTime::class)
// Propagates opt-in due to DateProvider in the signature
fun getDate(dateProvider: DateProvider = DateProvider()): Date

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

При распространении требований к явному согласию важно понимать, что если элемент API становится стабильным и больше не требует явного согласия, любые другие элементы API, для которых это требование сохраняется, остаются экспериментальными. Например, предположим, что автор библиотеки удаляет требование явного согласия для функции getDate(), поскольку теперь она стабильна:

// Library code
// No opt-in requirement
fun getDate(): Date {
    val dateProvider: DateProvider
    // ...
}

Если использовать функцию displayDate(), не удаляя аннотацию явного согласия, она останется экспериментальной, даже если согласие больше не требуется:

// Client code

// Still experimental!
@MyDateTime 
fun displayDate() {
    // Uses a stable library function
    println(getDate())
}

Дать согласие на использование нескольких API

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

@ExperimentalCoroutinesApi
@FlowPreview

Или, вместо этого, с помощью @OptIn:

@OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)

Дать согласие для файла

Чтобы использовать 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, можно добавить аргументы следующим образом:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

tasks.named<KotlinCompilationTask<*>>("compileKotlin").configure {
    compilerOptions.optIn.add("org.mylibrary.OptInAnnotation")
}
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
// ...

tasks.named('compileKotlin', KotlinCompilationTask) {
    compilerOptions {
        optIn.add('org.mylibrary.OptInAnnotation')
    }
}

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

kotlin {
    compilerOptions {
        optIn.add("org.mylibrary.OptInAnnotation")
    }
}
kotlin {
    compilerOptions {
        optIn.add('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 библиотеки может быть стабильным для использования, но не для наследования, поскольку в будущем в него могут быть добавлены новые абстрактные функции. Авторы библиотек могут обеспечить это, пометив аннотацией @SubclassOptInRequired открытые или абстрактные классы и нефункциональные интерфейсы.

Чтобы дать согласие на использование такого элемента API и расширить его в своём коде, примените аннотацию @SubclassOptInRequired со ссылкой на класс аннотации. Например, предположим, что вы хотите использовать интерфейс CoreLibraryApi, для которого требуется явное согласие:

// Library code
@RequiresOptIn(
 level = RequiresOptIn.Level.WARNING,
 message = "Interfaces in this library are experimental"
)
annotation class UnstableApi()

@SubclassOptInRequired(UnstableApi::class)
// An interface requiring opt-in to extend
interface CoreLibraryApi 

В коде перед созданием нового интерфейса, наследующего интерфейс CoreLibraryApi, добавьте аннотацию @SubclassOptInRequired со ссылкой на класс аннотации UnstableApi:

// Client code
@SubclassOptInRequired(UnstableApi::class)
interface SomeImplementation : CoreLibraryApi

Обратите внимание: если применить аннотацию @SubclassOptInRequired к классу, требование явного согласия не распространяется на внутренние или вложенные классы:

// Library code
@RequiresOptIn
annotation class ExperimentalFeature

@SubclassOptInRequired(ExperimentalFeature::class)
open class FileSystem {
    open class File
}

// Client code

// Opt-in is required
class NetworkFileSystem : FileSystem()

// Nested class
// No opt-in required
class TextFile : FileSystem.File()

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

// Client code
// With @OptIn annotation
@OptInRequired(UnstableApi::class)
interface SomeImplementation : CoreLibraryApi

// With annotation referencing annotation class
// Propagates the opt-in requirement further
@UnstableApi
interface SomeImplementation : CoreLibraryApi

Требовать явного согласия на использование API

Вы можете требовать от пользователей своей библиотеки явного согласия, прежде чем они смогут использовать ваше 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.

Кроме того, можно предоставить пользователям API message. Компилятор показывает это сообщение пользователям, которые пытаются использовать 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

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

@MyDateTime
class DateProvider

@MyDateTime
fun getTime(): Time {}

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

  • Нельзя аннотировать поле хранения или геттер свойства — можно аннотировать только само свойство.

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

Требовать явного согласия на расширение API

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

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

  • Сложны или уязвимы для реализации, например отдельные функции, которые должны работать согласованно.

  • Имеют контракт, который в будущем может быть ослаблен несовместимым с предыдущими версиями образом для внешних реализаций, например при изменении входного параметра T на допускающую null версию T?, если ранее код не учитывал значения null.

В таких случаях можно требовать от пользователей явного согласия на использование API, прежде чем они смогут расширять его. Пользователи могут расширять ваше API, наследуясь от него или реализуя абстрактные функции. Аннотация @SubclassOptInRequired позволяет требовать явного согласия для открытых или абстрактных классов и нефункциональных интерфейсов.

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

@RequiresOptIn(
 level = RequiresOptIn.Level.WARNING,
 message = "Interfaces in this library are experimental"
)
annotation class UnstableApi()

@SubclassOptInRequired(UnstableApi::class)
// An interface requiring opt-in to extend
interface CoreLibraryApi 

Обратите внимание: при использовании аннотации @SubclassOptInRequired для требования явного согласия это требование не распространяется на внутренние или вложенные классы.

Пример использования аннотации @SubclassOptInRequired в реальном API можно найти в интерфейсе SharedFlow библиотеки kotlinx.coroutines.

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

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

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

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

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

© 2010–2026 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