2017-07-28 1 views
6

Ich versuche, die WHEN Klausel mit einem > oder < Vergleich zu verwenden.Verwenden Kotlin WHEN-Klausel für <, <=, > =,> Vergleiche

Dies wird nicht kompiliert. Gibt es eine Möglichkeit, den normalen Satz boolescher Operatoren (< < =,> =>) in einem Vergleich zu verwenden, um dies zu ermöglichen?

val foo = 2 

// doesn't compile 
when (foo) { 
    > 0 -> doSomethingWhenPositive() 
    0 -> doSomethingWhenZero() 
    < 0 -> doSomethingWhenNegative() 
} 

Ich habe versucht, einen unbegrenzten Bereich Vergleich zu finden, aber konnte dies auch nicht funktionieren? Ist es möglich, dies als unbegrenzten Bereich zu schreiben?

Sie können den gesamten Ausdruck in den zweiten Teil einfügen, was OK ist, aber scheint wie unnötige Duplizierung. Zumindest kompiliert und funktioniert es.

Aber ich bin nicht sicher, dass das einfacher ist als die if-else Alternative, die wir seit Jahren machen. Etwas wie:

if (foo > 0) { 
    doSomethingWhenPositive() 
} 
else if (foo < 0) { 
    doSomethingWhenNegative() 
} 
else { 
    doSomethingWhenZero() 
} 

Natürlich sind reale Probleme komplexer als die oben, und die WHEN Klausel ist attraktiv, aber nicht funktioniert, wie ich für diese Art von Vergleich erwarten.

Antwort

6

Selbst eine flexible Sprache wie Kotlin hat keine "elegante"/DRY-Lösung für jeden einzelnen Fall.

Sie können so etwas wie schreiben:

when (foo) { 
    in 0 .. Int.MAX_VALUE -> doSomethingWhenPositive() 
    0 -> doSomethingWhenZero() 
    else -> doSomethingWhenNegative() 
} 

Aber dann hängen Sie vom Variablentyp.

Ich glaube, das folgende Formular die idiomatische in Kotlin ist:

when { 
    foo > 0 -> doSomethingWhenPositive() 
    foo == 0 -> doSomethingWhenZero() 
    else  -> doSomethingWhenNegative() 
} 

Ja ... es gibt einige (minimal) Code-Duplizierung.

Einige Sprachen (Ruby ?!) versuchten, für jeden Fall eine über-elegante Form zu bieten - aber es gibt einen Kompromiss: Die Sprache wird komplexer und schwieriger für einen Programmierer, Ende-zu-Ende zu kennen.

My 2 cents ...

3

Die grammar für einen when Zustand ist wie folgt:

whenCondition (used by whenEntry) 
    : expression 
    : ("in" | "!in") expression 
    : ("is" | "!is") type 
    ; 

Das bedeutet, dass Sie nur is oder in als Sonderfälle verwenden können, die nicht sein müssen ein voller Ausdruck; alles andere muss ein normaler Ausdruck sein. Da > 0 kein gültiger Ausdruck ist, wird dieser nicht kompiliert.

Darüber hinaus sind Bereiche in Kotlin geschlossen, so dass Sie nicht mit einem unbegrenzten Bereich versuchen können.

Stattdessen sollten Sie die when Anweisung mit einem vollen Ausdruck, wie in Ihrem Beispiel verwenden:

when { 
    foo > 0 -> doSomethingWhenPositive() 
    foo < 0 -> doSomethingWhenNegative() 
    else -> doSomethingWhenZero() 
} 

Oder alternativ:

when { 
    foo < 0 -> doSomethingWhenNegative() 
    foo == 0 -> doSomethingWhenZero()   
    foo > 0 -> doSomethingWhenPositive()   
} 

, die besser lesbar sein.

+0

Es ist interessant, die Grammatik zu sehen. Also sieht der erste Ausdruck so aus, als müsste er ein Ausdruck sein, der den Booleschen Wert zurückgibt, was ich in meinem Beispiel verwendet habe, das kompiliert wurde. Ist das richtig. Der zweite Ausdruck mit der "in" -Klausel ist ein Ausdruck, der eine Art von Sammlung zurückgibt, und das "ist" ist einfach eine Typdeklaration. Recht? Wie auch immer, schätze den vollen Ausdruck für jeden Fall ist die sauberste Option hier. –

1

Sie möchten, dass Ihr Code elegant ist, also warum bleiben Sie auf dem when Ausdruck. Kotlin ist flexibel genug, um eine neue Erweiterung zu erstellen.

Zuerst sollten wir behaupten, dass wir hier nur eine Comparable<T> übergeben können, weil Sie den Wert vergleichen müssen.

Dann haben wir unseren Rahmen:

fun <T: Comparable<T>> case(target: T, tester: Tester<T>.() -> Unit) { 
    val test = Tester(target) 
    test.tester() 
    test.funFiltered?.invoke() ?: return 
} 
class Tester<T : Comparable<T>>(val it: T) { 
    var funFiltered: (() -> Unit)? = null 
    infix operator fun Boolean.minus(block:() -> Unit) { 
     if (this && funFiltered == null) funFiltered = block 
    } 

    fun lt(arg: T) = it < arg 
    fun gt(arg: T) = it > arg 
    fun ge(arg: T) = it >= arg 
    fun le(arg: T) = it <= arg 
    fun eq(arg: T) = it == arg 
    fun ne(arg: T) = it != arg 
    fun inside(arg: Collection<T>) = it in arg 
    fun inside(arg: String) = it as String in arg 
    fun outside(arg: Collection<T>) = it !in arg 
    fun outside(arg: String) = it as String !in arg 
} 

Danach haben wir elegant Code haben wie:

case("g") { 
    (it is String) - { println("hello") } // normal comparison, like `is` 
    outside("gg") - { println("gg again") } // invoking the contains method 
} 

case(233) { 
    lt(500) - { println("less than 500!") } 
    // etc. 
} 

Wenn Sie zufrieden sind, können Sie die minus Funktion compareTo und Rückkehr umbenennen 0. Auf diese Weise können Sie die - durch => ersetzen, die wie Scala aussieht.

+0

Dies ist ein nützliches Beispiel dafür, etwas Komplexeres zu tun, als ich hier brauche. Ich habe vor, nur die WHEN-Standardklausel zu verwenden, aber ich möchte auf dieses Beispiel für etwas hinweisen, das ähnlicher ist. –

+1

Ein solches Framework ist skalierbar, Sie können es auf viele Arten erweitern, wie zum Beispiel die Mustererkennung. – ice1000

Verwandte Themen