ProgrammatieMiddle Kotlin Developer

Wat zijn scope-functies in Kotlin (let, also, run, apply, with)? Wat is het verschil tussen deze functies, hoe kies je ze voor verschillende taken, welke nuances kunnen zich voordoen bij hun gebruik? Geef voorbeelden.

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Scope-functies ("gebied-functies") in Kotlin zijn standaardfuncties (let, also, run, apply, with) die het mogelijk maken om de uitvoeringscontext van een codeblok voor een object te beheren. Ze verschillen in:

  • type teruggegeven waarde,
  • hoe het object toegankelijk is binnen het blok: via it of via this.

Korte vergelijking:

Functiethis/itGeeft terugWaarvoor?
letitresultaatkettingoperaties, werken met nullable, mappen
alsoitobjectbijwerkingen, logging, debugging
runthisresultaatberekeningen, initialisatie met teruggeven
applythisobjectconfiguratie van object, builders
withthisresultaatwerken met externe API's, object "van buiten"

Voorbeelden:

  • let: handig als object nullable is:
val str: String? = "Text" str?.let { println(it.length) }
  • apply: instellen van een object:
val paint = Paint().apply { color = Color.RED strokeWidth = 2f }
  • run: uitvoeren op een object, resultaat teruggeven:
val length = "abcde".run { length }
  • with: voor werken met een extern object:
val sb = StringBuilder() with(sb) { append("Hello, ") append("world!") toString() }
  • also: voor bijwerkingen (bijvoorbeeld logs):
val list = mutableListOf(1, 2, 3) list.also { println("Before: $it") }.add(4)

Let op:

  • let maakt een kopie van het object in it, het is niet handig om de eigenschappen van het object te wijzigen.
  • apply en also geven altijd het oorspronkelijke object terug (this / it), handig voor builders.
  • run/with worden vaak verward: with is een gewone functie, geen extension.

Vraag met een valstrik.

Wat is het verschil tussen let en also?

Antwoord:

  • Beide gebruiken it binnen het blok,
  • let geeft het resultaat van de lambda terug, wordt vaak gebruikt voor kettingen van transformaties,
  • also geeft het oorspronkelijke object terug, gebruikt voor bijwerkingen (logging, debugging), om niet in de transformatieketen te interfereren.

Voorbeeld:

val result = listOf(1).also { println(it) }.map { it * 2 } // resultaat — List<Int>

Voorbeelden van echte fouten door gebrek aan kennis van deze nuances:


Verhaal

Een nieuweling gebruikte let om een object in te stellen, denkend dat dit de toestand "in de keten" kon veranderen. Hierdoor kreeg hij na het beëindigen van de configuratieblok niet het object, maar het resultaat van de lambda (bijvoorbeeld niets), waardoor de keten van het opbouwen van DSL werd verbroken.


Verhaal

Bij het schrijven van code voor het werken met nullable-objecten, gebruikten ze run in plaats van let, zonder het verschil in de teruggegeven waarde op te merken. Uiteindelijk verschilde het resultaat van de uitdrukking van wat werd verwacht, verschenen er null waar dit niet had moeten zijn — de logica van de applicatie brak.


Verhaal

In een grote builder gebruikten ze per ongeluk with voor interne objecten, denkend aan het extensiepatroon. Aangezien with geen extensiefunctie is, werkte de keten van meerdere with-blokken niet correct, werden interne aanroepen verward en gingen ze buiten het actuele object. Het was nodig om de hiërarchie van objectcreatie volledig opnieuw te schrijven.