我正在学习Kotlin,阅读lateinit
关键字让我怀疑它是否有用。请考虑以下代码:
var testString: String? = null
lateinit var lateTestString: String
fun print() {
print(testString?.length)
print(lateTestString.length)
}
这里获取字符串长度的唯一区别是使用?.
运算符检查它是否为null。使用lateinit
快捷方式,在访问属性或调用方法时不必添加额外的问号?仅仅通过这个事实,我认为除了在访问lateinit
时获得异常时,还需要添加额外的问号。
更多的研究表明,lateinit
适用于尚未初始化变量的注射和/或单元测试,但它会是。但是,是否不值得额外?.
而不仅仅.
才能避免异常风险?
答案 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)
}