Scope functions i Kotlin är fem funktioner i standardbiblioteket (let, run, with, apply, also) som utför ett kodblock i kontexten av ett objekt. De skiljer sig åt i hur man får åtkomst till objektet (via it eller this) och returvärdet (kontextobjekt eller resultatet av lambdan). Enligt Kotlin-dokumentationen (2026) minskar rätt val av scope function boilerplate-koden med 25–40%. Scope functions hjälper till att skriva initiering, konfiguration och transformationer av objekt i deklarativ stil.
Huvudpunkter
Scope functions (omfångsfunktioner) — är en uppsättning av fem funktioner (let, run, with, apply, also) inbyggda i Kotlins standardbibliotek. Var och en tar emot en lambda och ändrar tillfälligt synlighetsomfånget så att koden inuti lambdan körs i kontexten av ett specifikt objekt. Detta undviker upprepning av objektnamnet vid flera anrop och grupperar relaterade operationer i ett block.
Två viktiga egenskaper skiljer scope functions åt: sättet att få åtkomst till kontextobjektet (via this eller it) och returvärdet (själva kontextobjektet eller resultatet av lambdan). Åtkomst via this gör objektet till en implicit mottagare — metoder och egenskaper anropas utan prefix. Åtkomst via it skickar objektet som en explicit parameter till lambdan. Att returnera objektet möjliggör kedjebyggen, att returnera resultatet möjliggör tilldelning av det transformerade värdet.
Historiskt sett uppstod scope functions som en ersättning för det klassiska Builder-mönstret och tillfälliga variabler för initiering. Istället för att skapa en separat builder-klass skriver programmeraren apply { egenskap1 = ...; egenskap2 = ... }. Detta minskar mängden kod och gör initieringen mer läsbar. I Kotlins ekosystem används scope functions i alla ramverk och bibliotek som ett standardspråkidiom.
Valet av rätt scope function bestäms av två frågor: vill du använda this eller it för åtkomst till objektet, och vill du returnera själva objektet eller resultatet av lambdan? Kombinationen av två binära egenskaper ger fyra möjliga varianter, och with har en speciell plats som den enda funktionen som inte är ett tillägg.
| Funktion | Åtkomst | Retur | Tillägg? | Typiskt scenario |
|---|---|---|---|---|
| let | it | resultat av lambda | ja | Transformation, null-kontroll |
| run | this | resultat av lambda | ja | Beräkning med kontext |
| with | this | resultat av lambda | nej | Gruppering av anrop |
| apply | this | kontextobjekt | ja | Initiering av egenskaper |
| also | it | kontextobjekt | ja | Sidoeffekter, loggning |
För konfiguration av objekt utan att returnera ett nytt värde använder du apply (åtkomst via this) eller also (åtkomst via it). För att beräkna ett nytt värde baserat på objektet använder du let (åtkomst via it) eller run (åtkomst via this). För att gruppera anrop utan kedja använder du with. Att följa detta schema gör koden förutsägbar för andra utvecklare som är bekanta med Kotlin.
apply — scope function som returnerar kontextobjektet och ger åtkomst till det via this. Det är det ideala verktyget för att initiera objektets egenskaper efter skapande. Inuti apply-blocket kan egenskaper ställas in utan att upprepa objektnamnet. Metoden returnerar själva objektet, vilket gör att apply kan bäddas in i kedjor eller användas i initierare.
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
}
I listningen konfigurerar apply ServerConfig genom att direkt via this få åtkomst till egenskaper (this utelämnas). Utan apply skulle man behöva skriva config.host = ..., config.port = ... — tre upprepade referenser till samma variabel. Objektreturen gör det möjligt att spara konfigurationsresultatet i val config. also, till skillnad från apply, skickar objektet via it och är lämpligt för sidoeffekter.
fun saveUser(user: User) {
validate(user).also { result ->
println("Valideringsresultat: $result")
}
val savedUser = user.also {
log("Saving user ${it.id}")
database.save(it)
}
}
I exemplet används also för loggning — genom att returnera det ursprungliga objektet utför det en sidoeffekt (utskrift av meddelande) utan att ändra objektet. Detta är en kedja: validate(user) returnerar User, also loggar resultatet och skickar användaren vidare. also är också användbart för att lägga till element i samlingar eller felsöka mitt i en transformationskedja.
let — scope function som returnerar resultatet av lambdan och skickar kontexten via it. Det är den primära funktionen för null-säkra transformationer: om objektet är nullable kommer kombinationen ?.let { } att utföra blocket endast vid ett icke-null-värde. let används också för att begränsa synlighetsomfånget för tillfälliga variabler och map-liknande transformationer från en typ till en annan.
fun findUser(id: Int): User?
val displayName = findUser(42)?.let { user ->
"${user.name} (${user.email})"
} ?: "Unknown user"
// let med samlingstransformation
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
it.toIntOrNull()
} ?: 0
I det första exemplet anropas let via ?. — blocket körs endast om findUser returnerade icke-null. Lambdan tar emot user via it (kan byta namn för tydlighetens skull) och returnerar en formaterad sträng. Om användaren inte hittas — Elvis-operatorn ?: ger ett standardvärde. I det andra exemplet omvandlar let en sträng till ett nummer med potentiell null.
run — motsvarigheten till let med åtkomst via this, som returnerar resultatet av lambdan. run är praktiskt för beräkningar där objektets kontext krävs men ett nytt värde returneras. Ett run()-anrop utan objekt (som run { ... }) skapar ett tillfälligt synlighetsomfång för variabler. with — icke-tillägg med åtkomst via this, lämpligt för att gruppera anrop utan kedja.
// run som kontextstyrd beräkning
val transformed = listOf(1, 2, 3).run {
filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]
// with för gruppering av anrop
val info = with(StringBuilder()) {
append("Name: ")
append("Alice")
toString()
}
I exemplet returnerar run på en lista resultatet av filtrering och mappning — själva transformationen, inte listan. with tar emot StringBuilder som argument (inte via punkt) och arbetar internt med this: append, append, toString. Resultatet av with — strängen info. Valet mellan run och with är ofta subjektivt, men with är att föredra när objektet skickas från en annan plats utan anropskedja.
with skiljer sig från de andra scope functions genom att det inte är en tilläggsfunktion. Den tar emot objektet som första argument och lambdan som andra. Inuti lambdan är objektet tillgängligt via this. with är praktiskt för att gruppera metodanrop på objektet utan att spara resultatet eller när man tillfälligt behöver “gå in” i kontexten för att läsa flera egenskaper.
val user = User("Alice", "alice@example.com", "Admin")
val summary = with(user) {
"User $name has role $role and email $email"
}
println(summary)
// with för initiering av UI-komponent
with(TextView(context)) {
text = "Hello"
textSize = 18.0f
setTextColor(Color.BLUE)
}
I det första exemplet bildar with strängen summary genom att direkt via this få åtkomst till användarens egenskaper. Utan with skulle man behöva skriva “User ${user.name} has role ${user.role}” — upprepad användning av user. I det andra exemplet grupperar with konfigurationen av TextView: alla metoder och egenskaper anropas på ett objekt utan upprepning. Nackdel med with — kan inte användas i en kedja eftersom det inte är ett tillägg och inte returnerar kontextobjektet.
Vanliga frågor
Använd apply — det returnerar objektet och ger åtkomst via this, vilket gör det möjligt att ställa in egenskaper utan att upprepa objektnamnet. also är lämpligt om en explicit it-parameter behövs för att skilja från objektets egenskaper.
let skickar kontexten via it (explicit parameter), run — via this (implicit mottagare). let är praktiskt för null-kontroller och transformationer, run — för beräkningar med kontext. Båda returnerar resultatet av lambdan.
with är inte ett tillägg — det tar emot objektet som argument. Använd with för att gruppera anrop när en kedja inte behövs. apply — tillägg som returnerar objektet, praktiskt i initierare och builder-mönster.
Ja, men var försiktig med this — nästlade this skapar förvirring. Använd let eller also med explicita namn för nästlade kontexter för att undvika tvetydighet vid referens till det yttre objektet.
Alla scope functions är inline, så de skapar ingen overhead för anonyma klasser. Prestandaskillnaden mellan dem är försumbar. Valet bör baseras på läsbarhet och konventioner, inte på hastighet.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också