Привет, Хабр!
Cегодня разберём экспериментальную фичу Kotlin 2.2 — контекстные параметры. C помощью контекстных параметров функции и свойства могут объявлять зависимости, которые неявно передаются при вызове.
Допустим, есть сервис логирования UserService, который нужно часто передавать во многие функции. Без контекстных параметров пришлось бы всюду писать fun outputMessage(users: UserService, msg: String). С параметрами контекста достаточно объявить функцию так:
interface UserService {
fun log(message: String)
}
context(users: UserService)
fun outputMessage(message: String) {
users.log("Log: $message")
}context указывает, что функция outputMessage ожидает в своём окружении объект UserService. То есть при вызове компилятор неявно подставит нужный сервис из контекста.
Также параметры контекста можно применять и к свойствам. Например:
context(users: UserService)
val firstUser: String
get() = users.findUserById(1)Этот синтаксис делает firstUser ленивым свойством, которое берёт UserService из контекста и возвращает пользователя по ID.
Kotlin разрешает контекстные параметры по типу в месте вызова: достаточно положить объект нужного типа в контекст с помощью стандартных функций with/run/apply или специального блока context(obj) { ... }. Если в одном месте окажется несколько объектов с одинаковым типом, компилятор выдаст ошибку неоднозначности.
Но если вызвать функцию без необходимого контекста, Kotlin тоже выдаст ошибку компиляции, все context‑параметры обязаны быть обеспечены объектом нужного типа.
Можно использовать context(_ : Type), если нужен только тип в контексте, а не именованно к нему обращаться. Тогда внутри функции объект доступен, но по имени _ обращаться к нему нельзя.
На данный момент контекстные параметры всё ещё экспериментальны. Основные ограничения:
Конструкторы не могут иметь
context‑параметров.Свойства с
contextне могут иметь полей или начальных значений.Свойства с
contextне могут использовать делегаты (by). То естьcontextможет стоять только перед функцией или передval/varбез инициализатора.
Чтобы опробовать эту фичу в своём проекте, нужно включить флаг компилятора -Xcontext-parameters. Например, в Gradle‑файле можно добавить:
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xcontext-parameters")
}
}Для наглядности ещё один пример: предположим, есть Logger и TransactionManager, которые часто используются вместе. С контекстными параметрами можно сделать так:
context(logger: Logger, tx: TransactionManager)
fun perform(data: Data) {
logger.debug("Start processing $data")
tx.run {
// операции в транзакции
}
logger.debug("End")
}
fun main() {
val data = Data()
with(ConsoleLogger()) {
with(TransactionManager()) {
perform(data) // Logger и TransactionManager предоставлены автоматически
}
}
}Вызов функции perform внутри вложенных with блоков автоматически предоставляет и Logger, и TransactionManager: внутри функции сразу доступны оба контекста.
Без контекстных параметров пришлось бы прокидывать оба объекта во все вызовы. Причём если забыть обернуть вызов в необходимый context, компиляция не пройдёт — Kotlin потребует нужные объекты.
Подытожим: context‑параметры позволяют вынести общие зависимости (сервисы, менеджеры и тому подобное) из сигнатур функций, сделав код чище и короче. Они автоматически подставляются по типу, а сама механика упрощает внедрение зависимостей и дизайн DSL. Фича пока доступна через EAP, но обещано, что в следующих версиях Kotlin она будет стабилизирована.

Если вам интересно применить Kotlin не только в проде, но и в тестовой инфраструктуре, посмотрите курс Kotlin QA Engineer. Он про автотесты для UI, бизнес-логики и API на разных платформах, DI (Hilt) и Jetpack Compose, плюс встраивание тестов в CI/CD с упором на нагрузку, стиль и базовую безопасность.
Для знакомства с форматом обучения и экспертами приходите на бесплатные демо-уроки:
15 января, 20:00. «Mutation Testing: как я узнал, что мои тесты с 95% coverage ничего не проверяют». Записаться
21 января, 20:00. «Особенности Kotlin в UI и API тестировании». Записаться
