我们必须用Kotlin中的所有Control-Flow表达式覆盖所有分支?

时间:2016-11-28 08:01:15

标签: kotlin control-flow

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

对于if

  

表达式需要else分支

对于when

  

如果不满足其他任何分支条件,则评估else分支。如果when用作表达式,则else分支是必需的,除非编译器能够证明所有可能的情况都包含在分支条件中。

问题

所以似乎没有办法在不覆盖所有分支的情况下制作控制流表达式,是不是?如果没有,有没有办法让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())
        }
    }
}

2 个答案:

答案 0 :(得分:3)

这里的诀窍是不要将if用作表达式。我的猜测是你将if放在let块上,它返回它的最后一个语句,因此使用"结果" if的{​​{1}},因此将其视为表达式。

我建议丢掉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())
    }
}

答案 1 :(得分:1)

  

所以似乎没有办法制作一个Control-Flow表达式   没有覆盖所有分支,是不是?

在第二种情况下

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

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

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

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