首页 > 解决方案 > 为什么这个不可为空的 val 变成“可空的”?

问题描述

所以我有一个简单的回调类:

class Callback<T>(
    val onResponse: (T) -> Unit,
    val onError:(Throwable)->Unit
)

现在我想实现一个处理错误的方法。可能有也可能没有callback需要调用的。

private fun handleServerError(error:IServerError, callback:Callback<*>? = null){
    val reason = error.cause

    when(reason){
        is Because.ServerRejectsLogin -> {
            doAsync { uiThread { mainActivity.longToast("sorry, your session timed out. please log in again.") } }
            IntentManager.doLogin(mainActivity)
        }
        else -> callback?.onError(reason)
    }
}

这给我一个错误:

引用具有可空类型,((Throwable) -> Unit)?使用显式?.invoke()进行类似函数的调用,而不是

它似乎期待的是

else -> callback?.onError?.invoke(reason)

我不太明白为什么。不为空的事实callback是否足以推导出必须有一个非空onError函数?

雪上加霜,如果我写

else -> callback?.let{it.onError(reason)}

然后它接受了,但不是在警告我我应该

删除多余的.let调用

标签: lambdakotlincallbacktype-inferencekotlin-null-safety

解决方案


如果您使用安全调用运算符调用在对象上调用的callback?.onError()函数,则语法将是正确的。但是,在这种情况下,您首先读取 的属性,然后对该属性返回的内容调用另一个函数。onErrorcallbackcallback

因此,而不是仅由一个步骤和两个部分组成的表达式:

callback   ?.onError()

您实际上拥有的是一个由三个部分组成的表达式,其中有两个运算符:

callback   ?.onError   ()

这里的最后一步()是调用返回invoke对象的运算符onError

callback   ?.onError   .invoke()

但是,由于该onError属性是使用安全调用运算符读取的,因此该对象可能是null. 在这种情况下,您不能使用invoke其运算符形式(顺便说一句,任何其他运算符也是如此),因此您必须明确写出它,并添加另一个安全调用:

callback   ?.onError   ?.invoke()

至于意图操作告诉您可以删除多余let的 : 这是一个错误,应该在问题跟踪器上报告。


推荐阅读