Menu
CoddyTech

lazy 和 lateinit

本课属于 Coddy Kotlin 学习旅程的“面向对象编程”单元。第 10 课,共 57 课。

by lazy { ... } 会将 val 的计算延迟到首次读取时,然后记住结果。它适用于计算开销大或不一定会用到的值:

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

在 main 中:

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

输出:

created
computing summary
total 7
total 7

这段代码块只运行一次:上面的第二次读取使用了已存储的结果。自定义 getter 每次读取时都会运行,而 lazy 只计算一次并缓存结果:

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

在 main 中:

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

输出:

4

lateinit var 声明一个稍后赋值的非空属性,例如在构造完成后通过设置方法赋值。在赋值之前读取它会引发异常,而 ::name.isInitialized 可以检查它是否已初始化:

class Screen {
    lateinit var title: String

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

在 main 中:

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

输出:

false
true
Home

如果创建时已知值,优先直接初始化。对于开销较大且可能用不到的 val,使用 lazy;只有当 var 的值确实要稍后才能获得时,才使用 lateinit。lateinit 不能用于 Int、Boolean 或其他基本类型。

val config by lazy { loadConfig() }     // 首次使用时计算,且只计算一次
lateinit var user: User                 // 构造后赋值
// lateinit var count: Int              // 错误:不能用于基本数据类型
challenge icon

挑战

简单

补全类 Document(val text: String)。添加 wordCount 作为 lazy 属性,统计单词数量(单词由单个空格分隔),并通过将 computations 加 1 来记录每次计算;再添加 lateinit var author: String,以及一个 credit() 方法,当作者已设置时返回 by Ada,否则返回 by unknown。

提供的代码会读取文本,将 wordCount 读取三次,在存在第二行时设置作者,并输出 words 5, computed 1, by Ada。

你的代码写在 Document.kt 中。Main.kt 包含提供的输入/输出代码,不能编辑。

亲手试试

fun main() {
    // 已提供的输入输出代码:保持原样。
    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 icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Kotlin 在线编辑器