2016-07-03 56 views
14

Con le classi sigillati è possibile utilizzare esaustive when espressioni e omettere la clausola else quando l'espressione restituisce un risultato:errore di compilazione Forza con le classi sigillate

sealed class SealedClass { 
    class First : SealedClass() 
    class Second : SealedClass() 
} 

fun test(sealedClass: SealedClass) : String = 
    when (sealedClass) { 
     is SealedClass.First -> "First" 
     is SealedClass.Second -> "Second" 
    } 

Ora, se dovessi aggiungere una Third-SealedClass, il compilatore si lamenterà che l'espressione when in test() non è esaustiva e ho bisogno di aggiungere una clausola per Third o else.

Mi chiedo se questo controllo può anche essere applicata quando test() non restituisce nulla:

fun test(sealedClass: SealedClass) { 
    when (sealedClass) { 
     is SealedClass.First -> doSomething() 
     is SealedClass.Second -> doSomethingElse() 
    } 
} 

Questo frammento non si rompe se si aggiunge Third. È possibile aggiungere una dichiarazione return prima del when, ma questo potrebbe essere facilmente dimenticato e potrebbe interrompersi se il tipo di ritorno di una delle clausole non è Unit.

Come posso essere sicuro di non dimenticare di aggiungere un ramo alle mie clausole when?

+2

Ho fatto la stessa domanda in Slack molto tempo fa, e AFAIR, non c'è altra soluzione che renderla un'espressione che restituisce qualcosa. Ma IntelliJ dovrebbe emettere un avvertimento se si dimentica una clausola, però (la mia domanda era per un enum, non una classe sigillata, ma dovrebbe essere la stessa). –

+1

Hmm, si. Ho notato che posso rendere "Any?", E forzare un valore di ritorno, ma si sente ancora un po 'hacky. – nhaarman

+0

Il mio preferito è il blocco di corsa. È leggibile, non cambia il tipo di ritorno della funzione da Unit a Any ?, e non è più o meno dimenticabile di aggiungere un return o un Any? tipo di ritorno. –

risposta

7

In ispirazione dalla risposta di Voddan, è possibile costruire una proprietà chiamata safe è possibile utilizzare:

val Any?.safe get() = Unit 

Per utilizzare:

when (sealedClass) { 
    is SealedClass.First -> doSomething() 
    is SealedClass.Second -> doSomethingElse() 
}.safe 

credo che viene ele identifica un messaggio più chiaro rispetto all'aggiunta di .let{} o all'assegnazione del risultato a un valore.


C'è un open issue sul inseguitore Kotlin che considera sostenere 'whens sigillati.

+0

Lo svantaggio di questo è che inquina il completamento automatico poiché questo metodo di estensione verrà visualizzato su ogni istruzione. – Tunga

12

Il modo per far rispettare esaustivo when è quello di rendere l'espressione utilizzando il suo valore:

sealed class SealedClass { 
    class First : SealedClass() 
    class Second : SealedClass() 
    class Third : SealedClass() 
} 

fun test(sealedClass: SealedClass) { 
    val x = when (sealedClass) { 
     is SealedClass.First -> doSomething() 
     is SealedClass.Second -> doSomethingElse() 
    } // ERROR here 

    // or 

    when (sealedClass) { 
     is SealedClass.First -> doSomething() 
     is SealedClass.Second -> doSomethingElse() 
    }.let {} // ERROR here 
}