Привет, Хабр!
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 тестировании». Записаться
