关键字lateinit是否不必要?

Sim*_*all 4 kotlin kotlin-lateinit

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

var testString: String? = null

lateinit var lateTestString: String

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

    print(lateTestString.length)
}
Run Code Online (Sandbox Code Playgroud)

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

更多研究表明,这lateinit对于尚未初始化变量的注射和/或单元测试是有益的,但它会是.但是,不值得拥有额外的东西?.而不仅仅是.为了不冒异常风险吗?

Ser*_*sev 16

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

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

  • @SimonZettervall:"然后它崩溃了" - 考虑另一种选择:系统_formally_继续运行,但它只是(默默地!)没有做它应该做的事情的一半.你根本不知道这一点.可能需要几个月才能发现错误.根据您的要求,这可能会导致更糟糕的结果.这是基本上的权衡. (4认同)
  • @SimonZettervall:嗯,通常你喜欢零安全,不要使用lateinit.但是当你_have to_(就像那个带有android活动的例子)时,你真的没有选择. (4认同)
  • 但是值**可以**为空,这不是问题吗?从 DI 的角度来看,它肯定会被设置,但这是唯一的情况吗?然后我认为 `lateinit` 是不必要的,因为它依赖于一个框架。它应该是一个 var then 因为它首先是 null 然后设置。无论如何,我确实理解您发送正确消息的意思,并且它使代码更清晰一点,这预计_始终_为非空值。然而,我也看到了这种方法的风险,因为 Kotlin 是作为一种“空安全语言”出现的,不使用美妙的非空方法是一种浪费。 (2认同)
  • @SimonZettervall:老实说,我认为这里没有违反安全措施.如果你忘记了这件事,你就不会得到一个神秘的NPE.此外,Marko指出了这样的措辞:它是__effectively__非null,但我们必须使它_technically_可以为空,因为类型系统不够强大. (2认同)

Mar*_*nik 5

使用lateinit快捷方式不必添加额外的问号

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

可以这么说,故意选择这两个!!是为了吸引人们对代码中“与类型系统打赌”的地方的注意。当在适当的地方使用时,这正是您想要的,但是现实生活中的项目中所有那些实际上是非 null 的变量呢?只是类型系统太弱而无法证明这一点?!!当我可以轻松确定它们已初始化时,我不想看到我的代码库周围的所有内容激增。这种噪音会减弱发出的强信号!!

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

实际上,很高兴看到 Kotlin 设计师将现实开发人员的担忧置于严格的类型形式主义之上。

  • 我并不奇怪,因为我是这个功能的重度用户,而且它对我来说是 Kotlin 最好的功能之一。当然,欢迎您完全忽略它并在任何地方严格使用可空类型,以及所有显式的 if 检查而不是 `!!` 和 `?`。不过,我建议不要对任何其他 Kotlin 程序员必须查看的任何代码执行此操作。 (3认同)
  • @SimonZettervall:在这种情况下,您会滥用“lateinit”。异步任务被取消/中止并不是一种特殊情况,如果这使得 var 未初始化,那么它显然必须可以为空。 (2认同)
  • 此外,“?.”不是“lateinit”的替代品,它改变了行为。如果您正在寻找方法来忽略 var 为“null”的事实,或者在这些情况下采取不同的行为,那么您并不是在谈论“lateinit”的用例。您正在讨论这样一种场景,其中代码实际上_可以_将“null”观察为合法值。 (2认同)