2016-07-03 7 views
14

Mit versiegelten Klassen können Sie Anspruch auf Vollständigkeit when Ausdrücke verwenden und die else-Klausel weglassen, wenn der Ausdruck ein Ergebnis zurückgibt:Force-Kompilierungsfehler mit versiegelten Klassen

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

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

Nun, wenn ich einen Third-SealedClass, den Compiler hinzuzufügen waren wird beschweren, dass die when Ausdruck in test() ist nicht erschöpfend, und ich muss eine Klausel für Third oder else hinzufügen.

Ich frage mich jedoch, ob diese Prüfung auch durchgesetzt werden kann, wenn test() nichts zurückliefert:

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

Dieser Code-Schnipsel nicht bricht, wenn Third hinzugefügt wird. Ich kann eine return Aussage vor when hinzufügen, aber das könnte leicht vergessen werden und kann brechen, wenn der Rückgabetyp einer der Klauseln nicht Unit ist.

Wie kann ich sicherstellen, dass ich nicht vergessen, einen Zweig zu meinen when Klauseln hinzuzufügen?

+2

Ich habe die gleiche Frage in Slack vor langer Zeit gestellt, und AFAIR, gibt es keine andere Lösung, als es einen Ausdruck zu machen, etwas zurückzugeben. Aber IntelliJ sollte eine Warnung ausgeben, wenn Sie eine Klausel vergessen (meine Frage war für eine Enum, nicht eine versiegelte Klasse, aber es sollte die gleiche sein). –

+1

Hmm, ja. Ich habe bemerkt, dass ich 'Any?' Zurückbringen kann und einen Rückgabewert erzwinge, aber es fühlt sich immer noch etwas hacky an. – nhaarman

+0

Mein bevorzugtes ist der Laufblock. Es ist lesbar, ändert nicht den Rückgabetyp der Funktion von Unit zu Any ?, und ist nicht mehr oder weniger vergesslich als das Hinzufügen einer Rückgabe oder eines Any? Rückgabetyp. –

Antwort

7

In Inspiration von Voddan Antwort, Sie eine Eigenschaft namens bauen können safe Sie verwenden können:

val Any?.safe get() = Unit 

zu benutzen:

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

ich denke, es prov ides eine klarere Nachricht als nur .let{} anhängen oder das Ergebnis einem Wert zuweisen.


Es gibt eine open issue auf dem Kotlin Tracker, die 'abgedichtet whens' zu unterstützen hält.

+0

Der Nachteil davon ist, dass es Autocomplete verschmutzt, da diese Erweiterungsmethode bei jeder Aussage angezeigt wird. – Tunga

12

Die Art und Weise erschöpfend when zu erzwingen ist es durch die Verwendung seines Wertes einen Ausdruck zu machen:

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 
} 
Verwandte Themen