Мы должны покрывать все ветви всеми выражениями Control-Flow в Котлине?

Я просмотрел документы с сайта Kotlin, есть только два выражения Control-Flow: if и when .

if :

выражение должно иметь ветвь else

when :

Филиал else оценивается, если ни одно из других условий ветвления не выполняется. Если в качестве выражения используется выражение, ветвь else является обязательным, если компилятор не может доказать, что все возможные случаи покрываются условиями ветвления.

Вопрос

Таким образом, кажется, что нет никакого способа сделать выражение Control-Flow без покрытия всех ветвей, правильно? Если нет, есть ли способ сделать выражение 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()) } } } 

    Трюк здесь заключается не в том, чтобы использовать if в качестве выражения. Я предполагаю, что вы положили if на блок let , который возвращает свой последний оператор, используя, таким образом, «результат» 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 в качестве выражения.

    PS

    В Котлине имеется довольно много мощных контрольных структур. Я лично предпочитаю эту версию:

     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()) } } 

    Таким образом, кажется, что нет никакого способа сделать выражение 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 

    Но было бы лучше избежать этого кода, потому что он менее читабельен.