关键字lateinit是否不必要?

时间:2018-01-10 13:07:56

标签: kotlin kotlin-lateinit

我正在学习Kotlin,阅读lateinit关键字让我怀疑它是否有用。请考虑以下代码:

var testString: String? = null

lateinit var lateTestString: String

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

    print(lateTestString.length)
}

这里获取字符串长度的唯一区别是使用?.运算符检查它是否为null。使用lateinit快捷方式,在访问属性或调用方法时不必添加额外的问号?仅仅通过这个事实,我认为除了在访问lateinit时获得异常时,还需要添加额外的问号。

更多的研究表明,lateinit适用于尚未初始化变量的注射和/或单元测试,但它会是。但是,是否不值得额外?.而不仅仅.才能避免异常风险?

4 个答案:

答案 0 :(得分:13)

lateinit关键字用于启用一个特定方案:当您的字段不能为空时,但您也无法在构造函数中初始化它或使用常量值。在您使用它之前,请确保初始化该值。如果不这样做,您会得到一个具有明确含义的特殊例外。

使用?.的lateinit用法和“普通”可空字段之间的区别在于后者传达了关于代码的错误消息:“这个东西有时可能为空”。事实上,当它不能的时候。它只是比平时更早初始化(例如,使用依赖注入而不是构造函数)。

答案 1 :(得分:3)

我不是来自Jetbrains团队,所以也许我在这里没有清晰的图片,但我同意你的观点,lateinit看起来不是一个好的构造。

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

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

  

L:嘿,Jetbrains!我们很懒,如果我们确定该房产将被初始化,我们不想要那个额外的问号。我们能否以某种方式标记它以克服Kotlin的无效安全性?

     

J:是的,当然!让我们打一下lateinit修饰符。

很棒的主意?

没有

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

所以,基本上,我们将问号与整个零安全性进行交易,以便有机会执行foo::isInitialized检查以防止UninitializedPropertyAccessException(或其他)。

答案 2 :(得分:3)

  

使用lateinit快捷方式无需添加额外的问号

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

这两个!!是故意选择吸引注意代码中的地方,你可以对类型系统进行赌注",可以这么说。当在适当的地方使用时,这正是你想要的,但是那些实际上是非空的的现实项目中的所有变量呢,只是类型系统太弱而无法证明它?当我能够轻松确定它们是否被初始化时,我讨厌在我的代码库周围看到!!的扩散。这种噪音会削弱!!发出的强烈信号。

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

实际上,很高兴看到Kotlin设计师将现实生活中的开发人员的关注置于严格的形式主义之上。

答案 3 :(得分:0)

lateint意味着稍后初始化
在此代码中,您会收到错误。 你必须在调用之前初始化lateTestString。

var testString: String? = null

lateinit var lateTestString: String

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

    print(lateTestString.length)
}