我们必须用 Kotlin 中的所有控制流表达式覆盖所有分支?

We have to cover all branches with all Control-Flow expressions in Kotlin?

我从 Kotlin 网站上看了 the docs,只有两个控制流表达式:ifwhen

对于if

the expression is required to have an else branch

对于when

The else branch is evaluated if none of the other branch conditions are satisfied. If when is used as an expression, the else branch is mandatory, unless the compiler can prove that all possible cases are covered with branch conditions.

问题

所以好像没有办法不覆盖所有分支的Control-Flow表达式,对吗?如果没有,有没有办法让控制流表达式错过一些分支;如果是,为什么?


会出现以下代码if must have both main and 'else' branches if used as an expression

override fun onReceive(context: Context?, intent: Intent?) {
    intent?.let {
        if (it.action == MySDK.BROADCAST_ACTION_LOGIN) {
            mListener.get()?.loggedOn(LoggedOnUserInfo.IT)
        }else if (it.action == MySDK.BROADCAST_ACTION_LOGOUT) {
            // Occur 'if must have both main and 'else' branches if used as an expression'
            mListener.get()?.loggedOut(LoggedOutUserInfo())
        }
    }
}

但是下面的代码通过了编译.....

override fun onReceive(context: Context?, intent: Intent?) {
    intent?.let {
        if (it.action == MySDK.BROADCAST_ACTION_LOGIN) {
            mListener.get()?.loggedOn(LoggedOnUserInfo.IT)
            context!!.unregisterReceiver(this) // only add this line to test.
        }else if (it.action == MySDK.BROADCAST_ACTION_LOGOUT) {
            mListener.get()?.loggedOut(LoggedOutUserInfo())
        }
    }
}

So it seems that there is no way to make a Control-Flow expression without covering all branches, Is it right?

第二种情况

mListener.get()?.loggedOn(LoggedOnUserInfo.IT)
context!!.unregisterReceiver(this)

不再是表达式,整个 if 块是一个语句。 但是,如果您确实需要表达式,您也可以在第一种情况下提供 elseUnit

if (it.action == MySDK.BROADCAST_ACTION_LOGIN) {
    mListener.get()?.loggedOn(LoggedOnUserInfo.IT)
} else if (it.action == MySDK.BROADCAST_ACTION_LOGOUT) {
    // Occur 'if must have both main and 'else' branches if used as an expression'
    mListener.get()?.loggedOut(LoggedOutUserInfo())
} else Unit

但最好避免使用此代码,因为它的可读性较差。

这里的技巧是不要使用 if 作为表达式。我的猜测是您将 if 放在 let 块中,returns 它的最后一个语句,因此使用 if 的“结果”,从而将其视为表达式.

我建议扔掉let函数(反正在这里也没用):

override fun onReceive(context: Context?, intent: Intent?) {
    if(intent != null) {
        if (intent.action == MySDK.BROADCAST_ACTION_LOGIN) {
            mListener.get()?.loggedOn(LoggedOnUserInfo.IT)
        } else if (intent.action == MySDK.BROADCAST_ACTION_LOGOUT) {
            mListener.get()?.loggedOut(LoggedOutUserInfo())
        }
    }
}

您的第二个版本可以编译,因为 context!!.unregisterReceiver(this) 的类型与 mListener.get()?.loggedOut(LoggedOutUserInfo()) 不同,这导致类型不匹配并阻止使用 if 作为表达式。

P.S.

Kotlin 有很多强大的控制结构。我个人更喜欢这个版本:

override fun onReceive(context: Context?, intent: Intent?) {
    intent ?: return
    when(intent.action) {
        MySDK.BROADCAST_ACTION_LOGIN -> mListener.get()?.loggedOn(LoggedOnUserInfo.IT)
        MySDK.BROADCAST_ACTION_LOGOUT -> mListener.get()?.loggedOut(LoggedOutUserInfo())
    }
}