Menu
Coddy logo textTech

lazy i lateinit

Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 10 z 57.

by lazy { ... } opóźnia obliczenie wartości val do momentu jej pierwszego odczytu, a następnie zapamiętuje wynik. Sprawdza się w przypadku wartości, których obliczenie jest kosztowne lub które nie zawsze są potrzebne:

class Report(val rows: List<Int>) {
    val summary: String by lazy {
        println("computing summary")
        "total ${rows.sum()}"
    }
}

Wewnątrz main:

val r = Report(listOf(3, 4))
println("created")
println(r.summary)
println(r.summary)

Wynik:

created
computing summary
total 7
total 7

Blok jest wykonywany raz: drugi odczyt powyżej użył zapisanego wyniku. W przeciwieństwie do własnego gettera, który jest wykonywany przy każdym odczycie, lazy oblicza wartość raz i ją buforuje:

class Demo {
    var reads = 0
    val viaGetter: Int
        get() { reads++; return 42 }
    val viaLazy: Int by lazy { reads++; 42 }
}

Wewnątrz main:

val d = Demo()
repeat(3) { d.viaGetter; d.viaLazy }
println(d.reads)

Wynik:

4

lateinit var deklaruje właściwość niebędącą wartością null, której wartość jest przypisywana później, po utworzeniu obiektu, na przykład przez metodę konfigurującą. Odczytanie jej przed przypisaniem wartości powoduje wyjątek, a ::name.isInitialized sprawdza, czy została zainicjalizowana:

class Screen {
    lateinit var title: String

    fun load(t: String) { title = t }
    fun ready() = ::title.isInitialized
}

Wewnątrz main:

val s = Screen()
println(s.ready())
s.load("Home")
println(s.ready())
println(s.title)

Wynik:

false
true
Home

Preferuj zwykłą inicjalizację, gdy wartość jest znana podczas tworzenia obiektu. Używaj lazy w przypadku kosztownego obliczeniowo elementu val, który może nie być potrzebny, a lateinit tylko w przypadku elementu var, którego wartość rzeczywiście pojawi się później; lateinit nie działa z Int, Boolean ani innymi typami prymitywnymi.

val config by lazy { loadConfig() }     // obliczana przy pierwszym użyciu, tylko raz
lateinit var user: User                 // przypisywana po utworzeniu obiektu
// lateinit var count: Int              // błąd: niedozwolone dla typów prostych
challenge icon

Wyzwanie

Łatwy

Uzupełnij klasę Document(val text: String). Dodaj wordCount jako właściwość lazy, która zlicza słowa (oddzielone pojedynczymi spacjami) i rejestruje każde obliczenie, zwiększając computations o 1, oraz lateinit var author: String z metodą credit(), która zwraca by Ada lub by unknown, gdy autor nie został ustawiony.

Dostarczony kod odczytuje tekst, trzy razy odczytuje wordCount, ustawia autora, jeśli dostępny jest drugi wiersz, i wypisuje words 5, computed 1, by Ada.

Twój kod umieść w pliku Document.kt. Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

fun main() {
    // Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
    val input = generateSequence(::readLine).toList()
    val doc = Document(input[0])
    val reads = List(3) { doc.wordCount }
    val words = reads.first()
    if (input.size > 1) doc.author = input[1]
    println("words $words, computed ${doc.computations}, ${doc.credit()}")
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Edytor online Kotlin