Scope functions — czym są, rodzaje i zastosowanie w Kotlin

Autor: IT Sectr Opublikowano: 2026-06-23 Czas czytania: 8 min

Scope functions w Kotlin to pięć funkcji standardowej biblioteki (let, run, with, apply, also), które wykonują blok kodu w kontekście obiektu. Różnią się sposobem dostępu do obiektu (przez it lub this) i zwracaną wartością (obiekt kontekstowy lub wynik lambdy). Według dokumentacji Kotlin (2026), odpowiedni wybór scope function redukuje kod boilerplate o 25–40%. Scope functions pomagają pisać inicjalizację, konfigurację i transformacje obiektów w deklaratywnym stylu.

Najważniejsze

  • Scope functions — pięć funkcji Kotlin (let, run, with, apply, also) do pracy w kontekście obiektu
  • Kontekst przez this — run, with, apply używają this, umożliwiając bezpośrednie wywoływanie metod obiektu
  • Kontekst przez it — let i also przekazują obiekt jako parametr it z jawnym nazwaniem
  • Zwrot obiektu — apply i also zwracają obiekt kontekstowy do łańcuchowania wywołań
  • Zwrot wyniku — let, run i with zwracają ostatnie wyrażenie lambdy

Czym są scope functions?

Scope functions (funkcje zakresu) — to zestaw pięciu funkcji (let, run, with, apply, also) wbudowanych w standardową bibliotekę Kotlin. Każda z nich przyjmuje lambdę i tymczasowo zmienia zakres widoczności tak, że wewnątrz lambdy kod wykonuje się w kontekście konkretnego obiektu. Pozwala to uniknąć powtarzania nazwy obiektu przy wielokrotnych wywołaniach i grupuje powiązane operacje w jeden blok.

Dwie kluczowe cechy różnią scope functions: sposób dostępu do obiektu kontekstowego (przez this lub przez it) oraz zwracana wartość (sam obiekt kontekstowy lub wynik lambdy). Dostęp przez this czyni obiekt niejawnym odbiorcą — metody i właściwości są wywoływane bez prefiksu. Dostęp przez it przekazuje obiekt jako jawny parametr lambdy. Zwrot obiektu umożliwia budowanie łańcuchów, zwrot wyniku — przypisanie przekształconej wartości.

Historycznie scope functions pojawiły się jako zamiennik klasycznego wzorca Builder i tymczasowych zmiennych do inicjalizacji. Zamiast tworzenia osobnej klasy builder, programista pisze apply { właściwość1 = ...; właściwość2 = ... }. Zmniejsza to ilość kodu i czyni inicjalizację bardziej czytelną. W ekosystemie Kotlin scope functions są używane we wszystkich frameworkach i bibliotekach jako standardowa idioma języka.

Porównanie scope functions: this vs it, zwrot obiektu vs wynik

Wybór odpowiedniej scope function zależy od dwóch pytań: czy chcesz używać this czy it do dostępu do obiektu, oraz czy chcesz zwrócić sam obiekt czy wynik lambdy. Kombinacja dwóch binarnych cech daje cztery możliwe warianty, a with zajmuje szczególne miejsce jako jedyna funkcja niebędąca rozszerzeniem.

FunkcjaDostępZwrotRozszerzenie?Typowy scenariusz
letitwynik lambdytakTransformacja, sprawdzanie null
runthiswynik lambdytakObliczenia z kontekstem
withthiswynik lambdynieGrupowanie wywołań
applythisobiekt kontekstowytakInicjalizacja właściwości
alsoitobiekt kontekstowytakEfekty uboczne, logowanie

Do konfiguracji obiektu bez zwracania nowej wartości używaj apply (dostęp przez this) lub also (dostęp przez it). Do obliczenia nowej wartości na podstawie obiektu używaj let (dostęp przez it) lub run (dostęp przez this). Do grupowania wywołań bez łańcuchowania używaj with. Przestrzeganie tego schematu czyni kod przewidywalnym dla innych programistów znających Kotlin.

apply i also: konfiguracja ze zwrotem obiektu

apply — scope function, która zwraca obiekt kontekstowy i zapewnia dostęp do niego przez this. To idealne narzędzie do inicjalizacji właściwości obiektu po utworzeniu. Wewnątrz bloku apply można ustawiać właściwości bez powtarzania nazwy obiektu. Metoda zwraca sam obiekt, co pozwala wbudować apply w łańcuchy lub używać w inicjalizatorach.

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
}

W listingu apply konfiguruje ServerConfig, odwołując się do właściwości bezpośrednio przez this (this pominięty). Bez apply trzeba by pisać config.host = ..., config.port = ... — trzy powtarzające się odwołania do tej samej zmiennej. Zwrot obiektu pozwala zachować wynik konfiguracji w val config. also, w przeciwieństwie do apply, przekazuje obiekt przez it i nadaje się do efektów ubocznych.

kotlin
fun saveUser(user: User) {
    validate(user).also { result ->
        println("Wynik walidacji: $result")
    }
    val savedUser = user.also {
        log("Saving user ${it.id}")
        database.save(it)
    }
}

W przykładzie also jest używane do logowania — zwracając oryginalny obiekt, wykonuje efekt uboczny (wyświetlenie komunikatu) bez modyfikacji obiektu. To łańcuch: validate(user) zwraca User, also loguje wynik i przekazuje użytkownika dalej. also jest również przydatny do dodawania elementów do kolekcji lub debugowania w środku łańcucha transformacji.

let i run: transformacje i obliczenia

let — scope function, która zwraca wynik lambdy i przekazuje kontekst przez it. To podstawowa funkcja do null-bezpiecznych transformacji: jeśli obiekt jest nullable, kombinacja ?.let { } wykona blok tylko przy wartości niepustej. let jest również używane do ograniczania zakresu widoczności zmiennych tymczasowych i transformacji map-podobnych z jednego typu na inny.

kotlin
fun findUser(id: Int): User?

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

// let z transformacją kolekcji
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
    it.toIntOrNull()
} ?: 0

W pierwszym przykładzie let jest wywoływane przez ?. — blok wykonuje się tylko jeśli findUser zwrócił nie null. Lambda przyjmuje user przez it (można przemianować dla jasności) i zwraca sformatowany string. Jeśli użytkownik nie został znaleziony — operator Elvisa ?: daje wartość domyślną. W drugim przykładzie let przekształca string na liczbę z potencjalnym null.

run — odpowiednik let z dostępem przez this, zwracający wynik lambdy. run jest wygodny do obliczeń, gdzie wymagany jest kontekst obiektu, ale zwracana jest nowa wartość. Wywołanie run() bez obiektu (jak run { ... }) tworzy tymczasowy zakres widoczności dla zmiennych. with — nierozszerzenie z dostępem przez this, odpowiednie do grupowania wywołań bez łańcuchowania.

kotlin
// run jako obliczenia kontekstowe
val transformed = listOf(1, 2, 3).run {
    filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]

// with do grupowania wywołań
val info = with(StringBuilder()) {
    append("Name: ")
    append("Alice")
    toString()
}

W przykładzie run na liście zwraca wynik filtrowania i mapowania — samo przekształcenie, a nie listę. with przyjmuje StringBuilder jako argument (nie przez kropkę) i wewnątrz pracuje z this: append, append, toString. Wynik with — string info. Wybór między run a with jest często subiektywny, ale with jest preferowane, gdy obiekt jest przekazywany z innego miejsca bez łańcucha wywołań.

with: kontekst bez rozszerzenia

with różni się od pozostałych scope functions tym, że nie jest funkcją-rozszerzeniem. Przyjmuje obiekt jako pierwszy argument, a lambdę jako drugi. Wewnątrz lambdy obiekt jest dostępny przez this. with jest wygodny do grupowania wywołań metod obiektu bez zapisywania wyniku lub gdy wymagane jest tymczasowe „wejście” w kontekst w celu odczytania kilku właściwości.

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

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

// with do inicjalizacji komponentu UI
with(TextView(context)) {
    text = "Hello"
    textSize = 18.0f
    setTextColor(Color.BLUE)
}

W pierwszym przykładzie with tworzy string summary, odwołując się do właściwości user bezpośrednio przez this. Bez with trzeba by pisać „User ${user.name} has role ${user.role}” — wielokrotne powtarzanie user. W drugim przykładzie with grupuje konfigurację TextView: wszystkie metody i właściwości są wywoływane na jednym obiekcie bez powtarzania. Wada with — brak możliwości użycia w łańcuchu, ponieważ nie jest rozszerzeniem i nie zwraca obiektu kontekstowego.

Często zadawane pytania

Którą scope function wybrać do inicjalizacji obiektu?

Użyj apply — zwraca obiekt i zapewnia dostęp przez this, umożliwiając ustawianie właściwości bez powtarzania nazwy obiektu. also jest odpowiedni, jeśli potrzebny jest jawny parametr it dla odróżnienia od właściwości obiektu.

Czym let różni się od run?

let przekazuje kontekst przez it (jawny parametr), run — przez this (niejawny odbiorca). let jest wygodny do sprawdzania null i transformacji, run — do obliczeń z kontekstem. Obie zwracają wynik lambdy.

Kiedy stosować with zamiast apply?

with nie jest rozszerzeniem — przyjmuje obiekt jako argument. Używaj with do grupowania wywołań, gdy łańcuch nie jest potrzebny. apply — rozszerzenie zwracające obiekt, wygodne w inicjalizatorach i wzorcach builder.

Czy można zagnieździć jedną scope function wewnątrz drugiej?

Tak, ale należy uważać na this — zagnieżdżone this tworzą zamieszanie. Używaj let lub also z jawnymi nazwami dla zagnieżdżonych kontekstów, aby uniknąć niejednoznaczności przy odwoływaniu się do obiektu zewnętrznego.

Która scope function jest najbardziej wydajna?

Wszystkie scope functions są inline, więc nie tworzą narzutu na klasy anonimowe. Różnica w wydajności między nimi jest pomijalnie mała. Wybór powinien opierać się na czytelności i konwencjach, a nie na szybkości.

Podsumowanie

  • Scope functions — pięć inline-funkcji Kotlin (let, run, with, apply, also) do wykonywania kodu w kontekście obiektu
  • apply zwraca obiekt kontekstowy z dostępem przez this — idealny do inicjalizacji właściwości
  • also zwraca obiekt kontekstowy z dostępem przez it — odpowiedni do logowania i efektów ubocznych
  • let zwraca wynik lambdy z dostępem przez it — podstawa null-bezpiecznych transformacji
  • run zwraca wynik lambdy z dostępem przez this — wygodny do obliczeń z kontekstem
  • with nie jest rozszerzeniem i zwraca wynik lambdy — odpowiedni do grupowania wywołań bez łańcucha
  • Kombinacja cech (this/it i zwrot obiektu/wyniku) określa wybór scope function dla każdego zadania

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również