Scope functions v Kotlinu je pět funkcí standardní knihovny (let, run, with, apply, also), které provádějí blok kódu v kontextu objektu. Liší se způsobem přístupu k objektu (přes it nebo this) a návratovou hodnotou (kontextový objekt nebo výsledek lambdy). Podle dokumentace Kotlinu (2026) správný výběr scope function snižuje boilerplate kód o 25–40%. Scope functions pomáhají psát inicializaci, konfiguraci a transformace objektů v deklarativním stylu.
Hlavní body
Scope functions (funkce rozsahu) — je sada pěti funkcí (let, run, with, apply, also) zabudovaných do standardní knihovny Kotlinu. Každá z nich přijímá lambdu a dočasně mění rozsah viditelnosti tak, že uvnitř lambdy se kód spouští v kontextu konkrétního objektu. To zabraňuje opakování názvu objektu při vícenásobných voláních a seskupuje související operace do jednoho bloku.
Dvě klíčové charakteristiky odlišují scope functions: způsob přístupu ke kontextovému objektu (přes this nebo it) a návratová hodnota (samotný kontextový objekt nebo výsledek lambdy). Přístup přes this činí objekt implicitním příjemcem — metody a vlastnosti jsou volány bez prefixu. Přístup přes it předává objekt jako explicitní parametr lambdy. Návrat objektu umožňuje vytváření řetězců, návrat výsledku — přiřazení transformované hodnoty.
Historicky se scope functions objevily jako náhrada klasického vzoru Builder a dočasných proměnných pro inicializaci. Místo vytváření samostatné builder třídy programátor napíše apply { vlastnost1 = ...; vlastnost2 = ... }. To snižuje množství kódu a činí inicializaci čitelnější. V ekosystému Kotlinu se scope functions používají ve všech frameworkách a knihovnách jako standardní idiom jazyka.
Výběr správné scope function je určen dvěma otázkami: chcete použít this nebo it pro přístup k objektu a chcete vrátit samotný objekt nebo výsledek lambdy. Kombinace dvou binárních charakteristik dává čtyři možné varianty a with zaujímá zvláštní místo jako jediná funkce, která není rozšířením.
| Funkce | Přístup | Návrat | Rozšíření? | Typický scénář |
|---|---|---|---|---|
| let | it | výsledek lambdy | ano | Transformace, kontrola null |
| run | this | výsledek lambdy | ano | Výpočet s kontextem |
| with | this | výsledek lambdy | ne | Seskupování volání |
| apply | this | kontextový objekt | ano | Inicializace vlastností |
| also | it | kontextový objekt | ano | Vedlejší efekty, logování |
Pro konfiguraci objektu bez návratu nové hodnoty použijte apply (přístup přes this) nebo also (přístup přes it). Pro výpočet nové hodnoty na základě objektu použijte let (přístup přes it) nebo run (přístup přes this). Pro seskupování volání bez řetězení použijte with. Dodržování tohoto schématu činí kód předvídatelným pro ostatní vývojáře obeznámené s Kotlinem.
apply — scope function, která vrací kontextový objekt a poskytuje k němu přístup přes this. Je to ideální nástroj pro inicializaci vlastností objektu po vytvoření. Uvnitř bloku apply lze nastavovat vlastnosti bez opakování názvu objektu. Metoda vrací samotný objekt, což umožňuje vložit apply do řetězců nebo použít v inicializátorech.
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
}
Ve výpisu apply konfiguruje ServerConfig a přistupuje k vlastnostem přímo přes this (this vynechán). Bez apply by se muselo psát config.host = ..., config.port = ... — tři opakující se odkazy na stejnou proměnnou. Návrat objektu umožňuje uložit výsledek konfigurace do val config. also na rozdíl od apply předává objekt přes it a je vhodný pro vedlejší efekty.
fun saveUser(user: User) {
validate(user).also { result ->
println("Výsledek validace: $result")
}
val savedUser = user.also {
log("Saving user ${it.id}")
database.save(it)
}
}
V příkladu se also používá k logování — vrácením původního objektu provádí vedlejší efekt (vytištění zprávy) bez změny objektu. Toto je řetězec: validate(user) vrací User, also loguje výsledek a předává uživatele dál. also je také užitečný pro přidávání prvků do kolekcí nebo ladění uprostřed řetězce transformací.
let — scope function, která vrací výsledek lambdy a předává kontext přes it. Je to hlavní funkce pro null-bezpečné transformace: pokud je objekt nullable, kombinace ?.let { } provede blok pouze při nenulové hodnotě. let se také používá k omezení rozsahu viditelnosti dočasných proměnných a map-podobným transformacím z jednoho typu na druhý.
fun findUser(id: Int): User?
val displayName = findUser(42)?.let { user ->
"${user.name} (${user.email})"
} ?: "Unknown user"
// let s transformací kolekce
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
it.toIntOrNull()
} ?: 0
V prvním příkladu se let volá přes ?. — blok se provede pouze pokud findUser vrátil nenulovou hodnotu. Lambda přijímá user přes it (lze přejmenovat pro přehlednost) a vrací formátovaný řetězec. Pokud uživatel není nalezen — Elvis operátor ?: poskytuje výchozí hodnotu. V druhém příkladu let transformuje řetězec na číslo s potenciálním null.
run — obdoba let s přístupem přes this, která vrací výsledek lambdy. run je vhodný pro výpočty, kde je vyžadován kontext objektu, ale vrací se nová hodnota. Volání run() bez objektu (jako run { ... }) vytváří dočasný rozsah viditelnosti pro proměnné. with — nerozšíření s přístupem přes this, vhodné pro seskupování volání bez řetězení.
// run jako kontextově řízený výpočet
val transformed = listOf(1, 2, 3).run {
filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]
// with pro seskupování volání
val info = with(StringBuilder()) {
append("Name: ")
append("Alice")
toString()
}
V příkladu run na seznamu vrací výsledek filtrování a mapování — samotnou transformaci, ne seznam. with přijímá StringBuilder jako argument (ne přes tečku) a uvnitř pracuje s this: append, append, toString. Výsledek with — řetězec info. Volba mezi run a with je často subjektivní, ale with je preferován, když je objekt předáván z jiného místa bez řetězce volání.
with se liší od ostatních scope functions tím, že není funkcí rozšíření. Přijímá objekt jako první argument a lambdu jako druhý. Uvnitř lambdy je objekt přístupný přes this. with je vhodný pro seskupování volání metod objektu bez ukládání výsledku nebo když je třeba dočasně „vstoupit“ do kontextu pro čtení několika vlastností.
val user = User("Alice", "alice@example.com", "Admin")
val summary = with(user) {
"User $name has role $role and email $email"
}
println(summary)
// with pro inicializaci UI komponenty
with(TextView(context)) {
text = "Hello"
textSize = 18.0f
setTextColor(Color.BLUE)
}
V prvním příkladu with tvoří řetězec summary a přistupuje k vlastnostem user přímo přes this. Bez with by se muselo psát „User ${user.name} has role ${user.role}” — vícenásobné opakování user. V druhém příkladu with seskupuje konfiguraci TextView: všechny metody a vlastnosti jsou volány na jednom objektu bez opakování. Nevýhoda with — nemožnost použití v řetězci, protože není rozšířením a nevrací kontextový objekt.
Často kladené otázky
Použijte apply — vrací objekt a poskytuje přístup přes this, umožňuje nastavení vlastností bez opakování názvu objektu. also je vhodný, pokud je potřeba explicitní parametr it pro odlišení od vlastností objektu.
let předává kontext přes it (explicitní parametr), run — přes this (implicitní příjemce). let je vhodný pro null kontroly a transformace, run — pro výpočty s kontextem. Oba vracejí výsledek lambdy.
with není rozšíření — přijímá objekt jako argument. Použijte with pro seskupování volání, když není potřeba řetězec. apply — rozšíření vracející objekt, vhodné v inicializátorech a builder vzorech.
Ano, ale buďte opatrní s this — vnořené this vytvářejí zmatek. Použijte let nebo also s explicitními názvy pro vnořené kontexty, aby se předešlo nejednoznačnosti při odkazování na vnější objekt.
Všechny scope functions jsou inline, takže nevytvářejí režii pro anonymní třídy. Rozdíl ve výkonu mezi nimi je zanedbatelný. Výběr by měl být založen na čitelnosti a konvencích, nikoli na rychlosti.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také