关键字 lateinit 是不必要的吗?

Is the keyword lateinit unnecessary?

我正在学习 Kotlin,阅读 lateinit 关键字让我怀疑它的用处。考虑这段代码:

var testString: String? = null

lateinit var lateTestString: String

fun print() {
    print(testString?.length)

    print(lateTestString.length)
}

这里获取字符串长度的唯一区别是使用 ?. 运算符检查它是否为空。使用 lateinit 是一种在访问属性或调用方法时不必添加额外问号的快捷方式吗?正因为如此,我认为在访问 lateinit 时添加额外的问号比获得异常更值得。

更多研究表明 lateinit 适用于变量尚未初始化的注入 and/or 单元测试,但它会初始化。但是,为了不冒异常风险,拥有额外的 ?. 而不是 . 是否不值得?

lateint表示稍后初始化
在这段代码中你得到错误。 您必须在调用 lateTestString 之前对其进行初始化。

var testString: String? = null

lateinit var lateTestString: String

fun print() {
    print(testString?.length)

    print(lateTestString.length)
}

lateinit 关键字的存在是为了启用一种特定情况:当您的字段 不能 为 null,但您也无法在构造函数中或使用一个常数值。您有责任确保在使用该值之前对其进行初始化。如果你不这样做,你会得到一个具有明确含义的特殊例外。

lateinit 用法与 ?. 的 "normal" 可空字段的区别在于后者传达了有关代码的错误消息:"this thing can sometimes be null"。事实上,它不能。它只是比平时晚初始化(例如,使用依赖注入而不是构造函数)。

我不是 Jetbrains 团队的成员,所以我在这里可能不清楚,但我同意你的看法,lateinit 看起来不是一个好的构造。

添加 lateinit 时的最初想法是我们有一些框架(提示:Android),有时框架的用户无法访问 class的构造函数(提示:Android 的 Activity class),他无法在构造函数或 init 块中初始化某些 属性。但是,由于这些 classes 具有某种生命周期,我们可以确定 属性 foo 将在 之前 被初始化它是第一次使用,因为,例如,初始化发生在 onCreate() 中,而 属性 用于 onResume(),稍后发生。

(在过去的某个地方,L - 懒惰的程序员,J - Jetbrains):

L: Hey, Jetbrains! We're lazy, we don't want that extra question mark if we're sure the property will be initialized. Could we please mark it somehow to overcome Kotlin's null safety?

J: Yes, sure! Let's slap in lateinit modifier.

好主意?

没有

因为在该语言的更高版本中,其创建者决定为 lateinit 属性添加新语法。我可能是错的(没有太注意它),但它看起来像 foo::isInitialized。原因是这个修改器被误用了(或者它从一开始就有缺陷?),所以我们需要附加一些额外的检查。

所以,基本上,我们正在用问号和整个空安全来换取执行 foo::isInitialized 检查以防止 UninitializedPropertyAccessException(或其他)的绝好机会。

Is using the lateinit a shortcut for not having to add that extra question mark

实际上它更接近 !! 的快捷方式。我在我的代码中经常使用它,原因我将尝试描述。

这两个 !! 是故意选择的,可以这么说,以引起人们对代码中您 "take a bet against the type system" 的地方的注意。当在适当的地方使用时,这正是你想要的,但是现实生活中的所有那些有效非空的变量呢,只是类型系统太弱而无法证明它?当我可以轻松确定它们已初始化时,我不想看到 !! 在我的代码库中扩散。这种噪音会削弱 !! 发送的强信号。

当您在代码中看到 lateinit var 时,您知道您只需查找周围上下文指定的任何初始化方法,以说服自己一切正常。检查它是否正确使用非常容易,而且我从未见过由此产生的错误。

看到 Kotlin 设计者将现实生活中的开发人员的顾虑置于严格的类型形式主义之上,实际上是非常令人高兴的。