Kotlin Academy · Lektion

tailrec-funktioner

Optimér rekursion

Lektion 3 af 413 trin

tailrec-funktioner er en gratis Kotlin Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Kotlin Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Kotlin Academy-kurset indeholder 4 lektioner i alt.

Hvad er halerekursion?

En funktion er halerekursiv, når det rekursive kald er den allersidste operation. Kotlin kan derefter optimere det til en løkke og undgå stakoverløb.

tailrec fun countdown(n: Int) {
    if (n < 0) return
    println(n)
    countdown(n - 1)
}

fun main() {
    countdown(3)
}

Modifikatoren tailrec

Tilføj modifikatoren tailrec, så omskriver kompileren rekursionen til iteration med konstant stakplads.

tailrec fun sum(n: Int, acc: Int = 0): Int {
    if (n == 0) return acc
    return sum(n - 1, acc + n)
}

fun main() {
    println(sum(100))
}

Akkumulatormønstret

For at gøre rekursionen halerekursiv skal du føre resultaterne videre i en akkumulator-parameter, så der ikke er noget tilbage at beregne efter kaldet.

tailrec fun factorial(n: Int, acc: Long = 1): Long {
    if (n <= 1) return acc
    return factorial(n - 1, acc * n)
}

fun main() {
    println(factorial(10))
}

Hvorfor kaldet skal være sidst

Hvis der sker noget efter det rekursive kald, f.eks. at resultatet multipliceres, er kaldet ikke i haleposition og kan ikke optimeres.

tailrec fun length(s: String, acc: Int = 0): Int {
    if (s.isEmpty()) return acc
    return length(s.drop(1), acc + 1)
}

fun main() {
    println(length("hello"))
}

Modeksempel på ikke-halerekursion

Denne fakultetsfunktion er IKKE halerekursiv, fordi multiplikationen sker, efter kaldet returnerer. Hvis du markerede den med tailrec, ville du få en advarsel.

fun badFactorial(n: Int): Long {
    if (n <= 1) return 1
    return n * badFactorial(n - 1)
}

fun main() {
    println(badFactorial(5))
}

Undgå stakoverløb

Dyb rekursion uden tailrec kan få programmet til at gå ned. Med tailrec kan selv store input behandles med konstant stakplads.

tailrec fun count(n: Int, acc: Int = 0): Int {
    if (n == 0) return acc
    return count(n - 1, acc + 1)
}

fun main() {
    println(count(100000))
}

Kontrol i kompileren

Hvis du markerer en funktion med tailrec, men kaldet ikke er i haleposition, udsender kompileren en advarsel og optimerer ikke funktionen. Stol på advarslen.

tailrec fun gcd(a: Int, b: Int): Int {
    if (b == 0) return a
    return gcd(b, a % b)
}

fun main() {
    println(gcd(48, 18))
}

Halerekursion kontra løkke

En funktion med tailrec kompileres til omtrent den samme kode som den tilsvarende løkke, men udtrykker algoritmen rekursivt.

tailrec fun powerOfTwo(n: Int, acc: Long = 1): Long {
    if (n == 0) return acc
    return powerOfTwo(n - 1, acc * 2)
}

fun main() {
    println(powerOfTwo(10))
}

Flere parametre

Halerekursive funktioner sender ofte flere tilstandsparametre videre, som alle opdateres i det rekursive kald.

tailrec fun fib(n: Int, a: Long = 0, b: Long = 1): Long {
    if (n == 0) return a
    return fib(n - 1, b, a + b)
}

fun main() {
    println(fib(20))
}

Omvend med tailrec

En akkumulator kan opbygge et resultat som en omvendt streng.

tailrec fun reverse(s: String, acc: String = ""): String {
    if (s.isEmpty()) return acc
    return reverse(s.drop(1), s.first() + acc)
}

fun main() {
    println(reverse("kotlin"))
}

En praktisk søgning

Iterative søgninger kan let omsættes til halerekursion.

tailrec fun indexOf(list: List<Int>, target: Int, i: Int = 0): Int {
    if (i >= list.size) return -1
    if (list[i] == target) return i
    return indexOf(list, target, i + 1)
}

fun main() {
    println(indexOf(listOf(5, 6, 7), 7))
}

Hurtig kontrol

Test din forståelse af tailrec-funktioner.

Opsummering

Du har lært om tailrec-funktioner:

  • tailrec omdanner rekursion i haleposition til en løkke og undgår stakoverløb.
  • Det rekursive kald skal være den sidste operation.
  • Brug en akkumulatorparameter for at opnå haleform.
  • Kompileren advarer, når en funktion ikke kan optimeres.
tailrec fun sum(n: Int, acc: Int = 0): Int =
    if (n == 0) acc else sum(n - 1, acc + n)

fun main() {
    println(sum(50))
}
Gratis at komme i gang

Lær Kotlin med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
51
Lektioner
203

Ofte stillede spørgsmål

Er lektionen “tailrec-funktioner” gratis?

Ja — alle 3 lektioner i læringssporet Kotlin Academy, inklusive “tailrec-funktioner”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Kotlin Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “tailrec-funktioner”?

Optimér rekursion Du øver dig i Kotlin Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Kotlin Academy?

Der kræves ingen tidligere erfaring. Kotlin Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “tailrec-funktioner”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Kotlin Academy-lektion?

Ja. Alle Kotlin Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Infix-funktioner
  2. Opbygning af DSL-lignende API'er
  3. tailrec-funktioner
  4. Hvornår De skal bruge hver af dem
← Tilbage til Kotlin Academy