Функції області видимості — що це, види та застосування в Kotlin

Автор: IT Sectr Опубліковано: 2026-06-23 Час читання: 8 хв

Функції області видимості в Kotlin — це п'ять функцій стандартної бібліотеки (let, run, with, apply, also), які виконують блок коду в контексті об'єкта. Вони розрізняються способом доступу до об'єкта (через it або this) і значенням, що повертається (контекстний об'єкт або результат лямбди). Згідно з документацією Kotlin (2026), правильний вибір функції області видимості скорочує шаблонний код на 25–40%. Функції області видимості допомагають писати ініціалізацію, конфігурацію та перетворення об'єктів у декларативному стилі.

Головне

  • Функції області видимості — п'ять функцій Kotlin (let, run, with, apply, also) для роботи в контексті об'єкта
  • Контекст через this — run, with, apply використовують this, дозволяючи викликати методи об'єкта безпосередньо
  • Контекст через it — let та also передають об'єкт як параметр it з явним іменуванням
  • Повернення об'єкта — apply та also повертають контекстний об'єкт для ланцюжків викликів
  • Повернення результату — let, run та with повертають останній вираз лямбди

Що таке функції області видимості?

Функції області видимості — це набір із п'яти функцій (let, run, with, apply, also), вбудованих у стандартну бібліотеку Kotlin. Кожна з них приймає лямбду та тимчасово змінює область видимості так, що всередині лямбди код виконується в контексті конкретного об'єкта. Це позбавляє від повторення імені об'єкта при множинних викликах і групує пов'язані операції в один блок.

Дві ключові характеристики розрізняють функції області видимості: спосіб доступу до контекстного об'єкта (через this або через it) і значення, що повертається (сам контекстний об'єкт або результат лямбди). Доступ через this робить об'єкт неявним отримувачем — методи та властивості викликаються без префікса. Доступ через it передає об'єкт як явний параметр лямбди. Повернення об'єкта дозволяє будувати ланцюжки, повернення результату — присвоювати перетворене значення.

Історично функції області видимості з'явилися як заміна класичному патерну Builder і тимчасовим змінним для ініціалізації. Замість створення окремого builder-класу розробник пише apply { властивість1 = ...; властивість2 = ... }. Це знижує кількість коду та робить ініціалізацію більш читабельною. В екосистемі Kotlin функції області видимості використовуються у всіх фреймворках і бібліотеках як стандартна ідіома мови.

Порівняння функцій області видимості: this vs it, повернення об'єкта vs результат

Вибір правильної функції області видимості визначається двома питаннями: чи хочете ви використовувати this або it для доступу до об'єкта, і чи хочете ви повернути сам об'єкт або результат лямбди. Комбінація двох бінарних ознак дає чотири можливих варіанти, а with займає особливе місце як єдина функція, що не є розширенням.

ФункціяДоступПоверненняРозширення?Типовий сценарій
letitрезультат лямбдитакПеретворення, null-перевірка
runthisрезультат лямбдитакОбчислення з контекстом
withthisрезультат лямбдиніГрупування викликів
applythisконтекстний об'єкттакІніціалізація властивостей
alsoitконтекстний об'єкттакПобічні дії, логування

Для конфігурації об'єкта без повернення нового значення використовуйте apply (доступ через this) або also (доступ через it). Для обчислення нового значення на основі об'єкта використовуйте let (доступ через it) або run (доступ через this). Для групування викликів без ланцюжка використовуйте with. Дотримання цієї схеми робить код передбачуваним для інших розробників, знайомих із Kotlin.

apply та also: конфігурація з поверненням об'єкта

apply — функція області видимості, яка повертає контекстний об'єкт і надає доступ до нього через this. Це ідеальний інструмент для ініціалізації властивостей об'єкта після створення. Всередині блоку apply можна встановлювати властивості без повторення імені об'єкта. Метод повертає сам об'єкт, що дозволяє вбудовувати apply у ланцюжки або використовувати в ініціалізаторах.

kotlin
data class ServerConfig(
    var host: String = "localhost",
    var port: Int = 8080,
    var useTls: Boolean = false
)

val config = ServerConfig().apply {
    host = "api.example.com"
    port = 443
    useTls = true
}

У лістингу apply конфігурує ServerConfig, звертаючись до властивостей безпосередньо через this (this опущений). Без apply довелося б писати config.host = ..., config.port = ... — три повторюваних посилання на одну й ту саму змінну. Повернення об'єкта дозволяє зберегти результат конфігурації в val config. also, на відміну від apply, передає об'єкт через it і підходить для побічних дій.

kotlin
fun saveUser(user: User) {
    validate(user).also { result ->
        println("Результат перевірки: $result")
    }
    val savedUser = user.also {
        log("Saving user ${it.id}")
        database.save(it)
    }
}

У прикладі also використовується для логування — повертаючи вихідний об'єкт, він виконує побічну дію (виведення повідомлення) без зміни об'єкта. Це ланцюжок: validate(user) повертає User, also логує результат і передає користувача далі. also також корисний для додавання елементів у колекції або налагодження всередині ланцюжка перетворень.

let та run: перетворення та обчислення

let — функція області видимості, яка повертає результат лямбди та передає контекст через it. Це основна функція для null-безпечних перетворень: якщо об'єкт nullable, комбінація ?.let { } виконає блок тільки при ненульовому значенні. let також використовується для обмеження області видимості тимчасових змінних і map-подібних перетворень одного типу в інший.

kotlin
fun findUser(id: Int): User?

val displayName = findUser(42)?.let { user ->
    "${user.name} (${user.email})"
} ?: "Unknown user"

// let із перетворенням колекції
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
    it.toIntOrNull()
} ?: 0

У першому прикладі let викликається через ?. — блок виконується, тільки якщо findUser повернув не null. Лямбда приймає user через it (можна перейменувати для ясності) і повертає форматований рядок. Якщо користувача не знайдено — Elvis-оператор ?: дає значення за замовчуванням. У другому прикладі let перетворює рядок у число з потенційним null.

run — аналог let із доступом через this, що повертає результат лямбди. run зручний для обчислень, де потрібен контекст об'єкта, але повертається нове значення. Виклик run() без об'єкта (як run { ... }) створює тимчасову область видимості для змінних. with — не-розширення з доступом через this, що підходить для групування викликів без ланцюжка.

kotlin
// run як обчислення на основі контексту
val transformed = listOf(1, 2, 3).run {
    filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]

// with для групування викликів
val info = with(StringBuilder()) {
    append("Name: ")
    append("Alice")
    toString()
}

У прикладі run на списку повертає результат фільтрації та маппінгу — саме перетворення, а не список. with приймає StringBuilder як аргумент (не через крапку) і всередині працює з this: append, append, toString. Результат with — рядок info. Вибір між run і with часто суб'єктивний, але with кращий, коли об'єкт передається з іншого місця без ланцюжка викликів.

with: контекст без розширення

with відрізняється від інших функцій області видимості тим, що не є функцією-розширенням. Вона приймає об'єкт першим аргументом, а лямбду — другим. Всередині лямбди об'єкт доступний через this. with зручний для групування викликів методів об'єкта без збереження результату або коли потрібно тимчасово "увійти" в контекст для читання кількох властивостей.

kotlin
val user = User("Alice", "alice@example.com", "Admin")

val summary = with(user) {
    "User $name has role $role and email $email"
}
println(summary)

// with для ініціалізації компонентів UI
with(TextView(context)) {
    text = "Hello"
    textSize = 18.0f
    setTextColor(Color.BLUE)
}

У першому прикладі with формує рядок summary, звертаючись до властивостей user безпосередньо через this. Без with довелося б писати "User ${user.name} has role ${user.role}" — багаторазове повторення user. У другому прикладі with групує конфігурацію TextView: всі методи та властивості викликаються на одному об'єкті без повторення. Недолік with — неможливість використання в ланцюжку, оскільки вона не є розширенням і не повертає контекстний об'єкт.

Часті запитання

Яку функцію області видимості вибрати для ініціалізації об'єкта?

Використовуйте apply — він повертає об'єкт і надає доступ через this, дозволяючи встановлювати властивості без повторення імені об'єкта. also підходить, якщо потрібен явний параметр it для відмінності від властивостей об'єкта.

Чим let відрізняється від run?

let передає контекст через it (явний параметр), run — через this (неявний отримувач). let зручний для null-перевірок і перетворень, run — для обчислень із контекстом. Обидві повертають результат лямбди.

Коли застосовувати with замість apply?

with не є розширенням — він приймає об'єкт аргументом. Використовуйте with для групування викликів, коли не потрібен ланцюжок. apply — розширення, що повертає об'єкт, зручне в ініціалізаторах і builder-патернах.

Чи можна вкласти одну функцію області видимості в іншу?

Так, але будьте обережні з this — вкладені this створюють плутанину. Використовуйте let або also з явними іменами для вкладених контекстів, щоб уникнути неоднозначності при зверненні до зовнішнього об'єкта.

Яка функція області видимості найпродуктивніша?

Всі функції області видимості — inline, тому вони не створюють накладних витрат на анонімні класи. Різниця в продуктивності між ними незначна. Вибір повинен ґрунтуватися на читабельності та конвенціях, а не на швидкості.

Підсумки

  • Функції області видимості — п'ять inline-функцій Kotlin (let, run, with, apply, also) для виконання коду в контексті об'єкта
  • apply повертає контекстний об'єкт із доступом через this — ідеальний для ініціалізації властивостей
  • also повертає контекстний об'єкт із доступом через it — підходить для логування та побічних дій
  • let повертає результат лямбди з доступом через it — основа для null-безпечних перетворень
  • run повертає результат лямбди з доступом через this — зручний для обчислень із контекстом
  • with не є розширенням і повертає результат лямбди — підходить для групування викликів без ланцюжка
  • Комбінація ознак (this/it і повернення об'єкта/результату) визначає вибір функції області видимості для кожного завдання

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також