【问题标题】:Kotlin why non-null assertion required despite null checkKotlin 为什么尽管进行了空检查,但仍需要非空断言
【发布时间】:2021-10-31 21:25:25
【问题描述】:

我正在尝试处理 Kotlin/Android 上的改造响应:

if (response.isSuccessful && response.body() != null) {
                    val result = response.body().result

首先我不明白响应如何成功并且正文为空。无论如何,如果我添加空检查,我也会得到“智能转换为‘xy’是不可能的,因为‘response.body()’是一个复杂的表达式”添加非空断言代码(!!) 实际上对我来说这是两个单独的警告,但为什么是 null-Assertion 请求?

【问题讨论】:

  • First I don't understand how the response can be successful and the body null。请检查 HTTP 204 代码
  • @Tenfour04 不过,javadoc 并没有说明 body 是非空的。正文可以反序列化为 null。
  • @Joffrey 不,尽管我认为它的编写方式模棱两可。这似乎至少暗示了isSuccessful 时存在一个值,但也许他们认为null 是一个有效的“反序列化值”。
  • 是的,我同意这里的文档不精确。这就是为什么我个人不会排除 null 在信息如此之少的情况下可能的价值

标签: kotlin retrofit2


【解决方案1】:

编译器无法知道body() 每次都保证返回相同的东西,因此它无法将其智能转换为非空值。此外,它不知道如果isSuccessful 为真,body 不会为空这一事实如此复杂。

因为我们从这个库的文档中知道它总是一样的,所以使用!! 是安全的。但是您也可以将该值复制到一个局部变量,并在您的空值检查中使用该变量。即使您误解了文档,您也可以确保您的代码是安全的。

我自己并没有真正使用 Retrofit,但通过阅读一点点,我知道你可以通过使用挂起函数在 Kotlin 中更自然地使用它,然后你就不必使用回调了和响应对象。因此,与其创建一个返回Call<MyData> 的函数,不如将调用排入队列,监听成功/失败,如果成功则解开主体;相反,您可以将函数标记为suspend 并直接返回MyData。调用函数时使用 try/catch 或runCatching,因为不成功时会抛出。

【讨论】:

  • 从上面对您问题的评论中,请小心。也许可以有一个空体的成功响应。我认为body() 的文档可能更清晰,因此您可能仍想进行空检查。相反,isSuccessful 检查可能会被删除,因为如果不成功将不会有 body()
  • 我将它与挂起函数一起使用,这并不意味着您不需要响应对象,如果您想抽象检查所有可能的空值并简单地返回获取的项目或错误。
  • 顺便说一句。这对使编程变得丑陋的想法很重要,您可以像我一样编写代码,但随后错误发生在其他地方,不直观,它需要了解内部工作原理等。
  • 另外,我正在为要使用的 API 编写客户端库,想象简单地提供一个函数 getListOfBooks(),传递改造结果并让每个库用户需要检查所有可能的空值并找出响应中他们正在等待的真实数据的位置。
【解决方案2】:

您需要将response.body() 设置为一个变量,然后检查它的可空性:

val body = response.body()
if (response.isSuccessful && body != null) {
    val result = body.result
}

【讨论】:

    猜你喜欢
    • 2018-08-06
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-21
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多