A scope functions Kotlinban a szabványos könyvtár öt függvénye (let, run, with, apply, also), amelyek egy kódblokkot egy objektum kontextusában hajtanak végre. Az objektumhoz való hozzáférés módjában (it vagy this segítségével) és a visszatérési értékben (kontextusobjektum vagy lambda eredménye) különböznek. A Kotlin dokumentáció (2026) szerint a scope function helyes megválasztása 25–40%-kal csökkenti a boilerplate kódot. Scope functions segítenek az objektumok inicializálásának, konfigurálásának és átalakításának deklaratív stílusban történő megírásában.
Főbb pontok
Scope functions (hatókör függvények) — öt függvényből álló készlet (let, run, with, apply, also), amelyek a Kotlin szabványos könyvtárába vannak beépítve. Mindegyikük fogad egy lambdát, és ideiglenesen megváltoztatja a láthatósági hatókört úgy, hogy a lambdán belüli kód egy adott objektum kontextusában hajtódik végre. Ez elkerüli az objektum nevének ismétlését többszörös hívásoknál, és a kapcsolódó műveleteket egy blokkba csoportosítja.
Két kulcsfontosságú jellemző különbözteti meg a scope functions-t: a kontextusobjektumhoz való hozzáférés módja (this vagy it segítségével) és a visszatérési érték (maga a kontextusobjektum vagy a lambda eredménye). A this segítségével történő hozzáférés implicit fogadóvá teszi az objektumot — a metódusok és tulajdonságok előtag nélkül hívhatók. Az it segítségével történő hozzáférés explicit paraméterként adja át az objektumot a lambdának. Az objektum visszaadása lehetővé teszi láncok építését, az eredmény visszaadása pedig az átalakított érték hozzárendelését.
Történelmileg a scope functions a klasszikus Builder minta és az inicializáláshoz használt ideiglenes változók helyettesítőjeként jelentek meg. Külön builder osztály létrehozása helyett a programozó ezt írja: apply { tulajdonság1 = ...; tulajdonság2 = ... }. Ez csökkenti a kód mennyiségét és olvashatóbbá teszi az inicializálást. A Kotlin ökoszisztémában a scope functions minden keretrendszerben és könyvtárban a nyelv szabványos idiómájaként használatos.
A megfelelő scope function kiválasztását két kérdés határozza meg: szeretné-e a this vagy az it használni az objektum eléréséhez, és szeretné-e magát az objektumot vagy a lambda eredményét visszaadni. Két bináris jellemző kombinációja négy lehetséges változatot ad, a with pedig különleges helyet foglal el, mint az egyetlen függvény, amely nem kiterjesztés.
| Függvény | Hozzáférés | Visszaadás | Kiterjesztés? | Tipikus forgatókönyv |
|---|---|---|---|---|
| let | it | lambda eredménye | igen | Átalakítás, null ellenőrzés |
| run | this | lambda eredménye | igen | Számítás kontextussal |
| with | this | lambda eredménye | nem | Hívások csoportosítása |
| apply | this | kontextusobjektum | igen | Tulajdonságok inicializálása |
| also | it | kontextusobjektum | igen | Mellékhatások, naplózás |
Objektum konfigurálásához új érték visszaadása nélkül használja az apply-t (hozzáférés this segítségével) vagy az also-t (hozzáférés it segítségével). Új érték kiszámításához az objektum alapján használja a let-et (hozzáférés it segítségével) vagy a run-t (hozzáférés this segítségével). Hívások csoportosításához láncolás nélkül használja a with-t. E séma követése kiszámíthatóvá teszi a kódot más, Kotlinban járatos fejlesztők számára.
apply — scope function, amely visszaadja a kontextusobjektumot, és this segítségével biztosít hozzáférést. Ez az ideális eszköz az objektum tulajdonságainak létrehozás utáni inicializálásához. Az apply blokkon belül a tulajdonságok beállíthatók az objektum nevének ismétlése nélkül. A metódus magát az objektumot adja vissza, lehetővé téve az apply beágyazását láncokba vagy használatát inicializálókban.
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
}
A listában apply konfigurálja a ServerConfig-ot, közvetlenül a this segítségével érve el a tulajdonságokat (this elhagyva). Apply nélkül config.host = ..., config.port = ... kellene írni — három ismétlődő hivatkozás ugyanarra a változóra. Az objektum visszaadása lehetővé teszi a konfiguráció eredményének elmentését a val config változóba. also az apply-pal ellentétben az it segítségével adja át az objektumot, és mellékhatásokhoz alkalmas.
fun saveUser(user: User) {
validate(user).also { result ->
println("Ellenőrzés eredménye: $result")
}
val savedUser = user.also {
log("Saving user ${it.id}")
database.save(it)
}
}
A példában also naplózásra használatos — az eredeti objektum visszaadásával mellékhatást hajt végre (üzenet kiírása) az objektum módosítása nélkül. Ez egy lánc: a validate(user) visszaadja a User-t, az also naplózza az eredményt és továbbadja a felhasználót. Az also hasznos továbbá elemek gyűjteményekhez adásához vagy hibakereséshez egy átalakítási lánc közepén.
let — scope function, amely visszaadja a lambda eredményét, és a kontextust az it segítségével adja át. Ez az elsődleges függvény null-biztos átalakításokhoz: ha az objektum nullable, a ?.let { } kombináció csak nem null érték esetén hajtja végre a blokkot. A let az ideiglenes változók láthatósági hatókörének korlátozására és map-szerű átalakításokra is használatos egyik típusból a másikba.
fun findUser(id: Int): User?
val displayName = findUser(42)?.let { user ->
"${user.name} (${user.email})"
} ?: "Unknown user"
// let gyűjteményátalakítással
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
it.toIntOrNull()
} ?: 0
Az első példában let a ?. segítségével hívódik meg — a blokk csak akkor hajtódik végre, ha a findUser nem null értéket adott vissza. A lambda az it segítségével fogadja a user-t (átnevezhető az érthetőség kedvéért) és visszaad egy formázott karakterláncot. Ha a felhasználó nem található — az Elvis operátor ?: alapértelmezett értéket ad. A második példában a let egy karakterláncot alakít át számmá potenciális null értékkel.
run — a let megfelelője this segítségével történő hozzáféréssel, amely visszaadja a lambda eredményét. A run kényelmes olyan számításokhoz, ahol az objektum kontextusa szükséges, de új érték kerül visszaadásra. A run() hívás objektum nélkül (mint run { ... }) ideiglenes láthatósági hatókört hoz létre változók számára. with — nem kiterjesztés this segítségével történő hozzáféréssel, alkalmas hívások láncolás nélküli csoportosítására.
// run kontextusvezérelt számításként
val transformed = listOf(1, 2, 3).run {
filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]
// with hívások csoportosításához
val info = with(StringBuilder()) {
append("Name: ")
append("Alice")
toString()
}
A példában a listán run visszaadja a szűrés és map-elés eredményét — magát az átalakítást, nem a listát. A with a StringBuilder-t argumentumként fogadja (nem pont segítségével) és belül a this-szel dolgozik: append, append, toString. A with eredménye — az info karakterlánc. A run és with közötti választás gyakran szubjektív, de a with előnyösebb, ha az objektum máshonnan kerül átadásra hívási lánc nélkül.
with abban különbözik a többi scope functions-tól, hogy nem kiterjesztési függvény. Első argumentumként az objektumot, másodikként a lambdát fogadja. A lambdán belül az objektum a this segítségével érhető el. A with kényelmes az objektum metódushívásainak csoportosításához az eredmény mentése nélkül, vagy amikor ideiglenesen „be kell lépni” a kontextusba több tulajdonság olvasásához.
val user = User("Alice", "alice@example.com", "Admin")
val summary = with(user) {
"User $name has role $role and email $email"
}
println(summary)
// with UI komponens inicializálásához
with(TextView(context)) {
text = "Hello"
textSize = 18.0f
setTextColor(Color.BLUE)
}
Az első példában with képezi a summary karakterláncot, közvetlenül a this segítségével érve el a user tulajdonságait. With nélkül „User ${user.name} has role ${user.role}” kellene írni — a user többszörös ismétlése. A második példában a with csoportosítja a TextView konfigurációját: az összes metódus és tulajdonság egy objektumon hívódik meg ismétlés nélkül. A with hátránya — nem használható láncban, mivel nem kiterjesztés és nem adja vissza a kontextusobjektumot.
Gyakran Ismételt Kérdések
Használja az apply-t — visszaadja az objektumot és this segítségével biztosít hozzáférést, lehetővé téve a tulajdonságok beállítását az objektum nevének ismétlése nélkül. Az also akkor megfelelő, ha explicit it paraméter szükséges az objektum tulajdonságaitól való megkülönböztetéshez.
let a kontextust az it segítségével adja át (explicit paraméter), a run — a this segítségével (implicit fogadó). A let null ellenőrzésekhez és átalakításokhoz alkalmas, a run — kontextussal végzett számításokhoz. Mindkettő visszaadja a lambda eredményét.
with nem kiterjesztés — az objektumot argumentumként fogadja. Használja a with-t hívások csoportosításához, ha nincs szükség láncra. apply — kiterjesztés, amely visszaadja az objektumot, kényelmes inicializálókban és builder mintákban.
Igen, de óvatosan a this-szel — az egymásba ágyazott this-ek zavart okoznak. Használjon let-et vagy also-t explicit nevekkel az egymásba ágyazott kontextusokhoz, hogy elkerülje a kétértelműséget a külső objektumra való hivatkozáskor.
Minden scope function inline, így nem hoznak létre többletterhelést névtelen osztályok számára. A teljesítménybeli különbség közöttük elhanyagolható. A választásnak az olvashatóságon és konvenciókon kell alapulnia, nem a sebességen.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is