Kotlin ‘when’-Anweisung vs. Java ‘switch’

Lesezeit: 5 Minuten

Benutzer-Avatar
Geob-o-matic

Der Musterabgleich in Kotlin ist nett und die Tatsache, dass der nächste Musterabgleich nicht ausgeführt wird, ist in 90 % der Anwendungsfälle gut.

Wenn die Datenbank in Android aktualisiert wird, verwenden wir die Java-Switch-Eigenschaft, um mit dem nächsten Fall fortzufahren, wenn wir keine Pause machen, damit der Code so aussieht:

switch (oldVersion) {
    case 1: upgradeFromV1();
    case 2: upgradeFromV2(); 
    case 3: upgradeFromV3();
}

Wenn also jemand eine App mit Version 1 der DB hat und die App-Version mit DB v2 verpasst hat, wird er den gesamten erforderlichen Upgrade-Code ausführen lassen.

In Kotlin konvertiert, erhalten wir ein Durcheinander wie:

when (oldVersion) {
    1 -> {
        upgradeFromV1()
        upgradeFromV2()
        upgradeFromV3()
    }
    2 -> {
        upgradeFromV2()
        upgradeFromV3()
    }
    3 -> {
        upgradeFromV3()
    }
}

Hier haben wir nur 3 Versionen, stellen Sie sich vor, wenn DB Version 19 erreicht.

Wie auch immer, macht, wenn man auf die gleiche Weise handelt, dann wechseln? Ich versuchte, ohne Glück fortzufahren.

  • Gerade gestolpert youtrack.jetbrains.com/issue/KT-771 dann irgendein Workaround?

    – Geob-o-matic

    14. Juni 2015 um 17:12 Uhr


  • Ich denke statistisch (keine Beweise, aber ich bin sicher, dass das Kotlin-Team Statistiken verwendet hat, um zu entscheiden), dass a switch in Java hat fast immer a break in jedem Fall, daher ist es für den allgemeinen Fall unbequem.

    – Jayson Minard

    5. Januar 2016 um 22:08 Uhr

Benutzer-Avatar
Bashor

Einfache, aber wortreiche Lösung ist:

if (oldVersion <= 1) upgradeFromV1()
if (oldVersion <= 2) upgradeFromV2()
if (oldVersion <= 3) upgradeFromV3()

Eine weitere mögliche Lösung mit Funktionsreferenzen:

fun upgradeFromV0() {}
fun upgradeFromV1() {}
fun upgradeFromV2() {}
fun upgradeFromV3() {}

val upgrades = arrayOf(::upgradeFromV0, ::upgradeFromV1, ::upgradeFromV2, ::upgradeFromV3)

fun upgradeFrom(oldVersion: Int) {
    for (i in oldVersion..upgrades.lastIndex) {
        upgrades[i]()
    }
}

  • Tolle Antwort, aber Sie können Rekursion verwenden, anstatt die Methode aus der for-Schleife aufzurufen

    – Suraj Vaishnav

    29. Dezember 2017 um 16:46 Uhr

  • @SurajVaishnav Warum ist die Rekursion besser? Verwenden tailrec wäre in Ordnung, aber die Schleife ist ziemlich einfach, IMO.

    – EM

    19. März 2020 um 22:30 Uhr

Benutzer-Avatar
Julian Delphiki

edit: Ursprüngliche Antwort unten. Folgendes mache ich gerade:

fun upgrade() {
    fun upgradeFromV1() { /* Do stuff */ }
    fun upgradeFromV3() { /* Do stuff */ }

    tailrec fun upgradeFrom(version: Int): Unit = when (version) {
        LATEST_VERSION -> {
            Config.version = version
        } 1 -> {
            upgradeFromV1()
            upgradeFrom(2)
        } in 2..3 -> {
            upgradeFromV3()
            upgradeFrom(4)
        } else -> {
            Log("Uncaught upgrade from $version")
            upgradeFrom(version+1)
    }

    upgradeFrom(Config.version)
}

Hier ist eine Variation der Antwort von @CAB:

fun upgrade(oldVersion: Int) {
    when (oldVersion) {
        latestVersion -> return
        1 -> upgradeFromV1()
        2 -> upgradeFromV2()
        3 -> upgradeFromV3()
    }
    upgrade(oldVersion + 1)
}

  • Füge hinzu ein Schwanzrez Modifikator für die (rekursiv aufgerufene) Funktion und Sie sind goldrichtig!

    – Jerzyna

    15. März 2017 um 10:17 Uhr

  • @Jerzyna in meiner aktuellen Lösung bearbeitet, die meiner Meinung nach etwas schöner ist.

    – Julian Delphiki

    20. April 2017 um 17:12 Uhr

Benutzer-Avatar
TAXI

Wie wäre es damit:

fun upgradeFromV3() {/* some code */}
fun upgradeFromV2() {/* some code */ upgradeFromV3()}
fun upgradeFromV1() {/* some code */ upgradeFromV2()}
fun upgradeFromV0() {/* some code */ upgradeFromV1()}

fun upgrade(oldVersion: Int) {
    when (oldVersion) {
        1 -> upgradeFromV1()
        2 -> upgradeFromV2()
        3 -> upgradeFromV3()
    }
}

Hinzugefügt:

Ich mag die Idee von @lukle, den Upgrade-Pfad als Liste zu definieren. Dies ermöglicht es, verschiedene Upgrade-Pfade für verschiedene Anfangsstufen zu definieren. Zum Beispiel:

  1. Einfacher schneller Weg von der veröffentlichten Version zur neuesten veröffentlichten Version
  2. Aufholpfad von der Hotfix-Version (könnte mehrere hintereinander sein), der nicht angewendet werden sollte, wenn von der vorherigen Vollversion zur nächsten Vollversion gewechselt wird

Dazu müssen wir wissen, ab welchen Elementen der Liste wir uns bewerben.

fun <Vs, V> Pair<Vs, V>.apply(upgrade: () -> Unit): (V) -> V {
    return { current: V ->
        if (first == current) {
            upgrade()
            second
        } else {
            current
        }
    }
}

val upgradePath = listOf(
        (0 to 10).apply  { /* do something */ },
        (5 to 15).apply  { /* do something */ },
        (10 to 20).apply { /* do something */ },
        (15 to 20).apply { /* do something */ },
        (20 to 30).apply { /* do something */ },
        (30 to 40).apply { /* do something */ }
)

fun upgrade(oldVersion: Int) {
    var current = oldVersion
    upgradePath.forEach { current = it(current) }
}

In diesem Code könnte Vs dasselbe sein wie V oder eine Art Sammlung von V-Werten mit Überschreibung equals(other: Any?): Boolean Methode.

Sie können einfach die for-Schleife mit when verwenden.

for (version in oldVersion..newVersion) when (version) {
    1 -> upgradeFromV1()
    2 -> upgradeFromV2()
    3 -> upgradeFromV3()
}

Benutzer-Avatar
Yarh

Es ist absolut möglich, aus einer offiziellen Referenz zu zitieren: Kontrollfluss: wenn, wann, für, während

If many cases should be handled in the same way, the branch conditions may be combined with a comma:

when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

Wenn also dieselbe Bedingungsliste kurz ist, können Sie sie durch Komma trennen oder Bereiche wie Bedingung in 1..10 verwenden, wie in anderen Antworten angegeben

  • Wie hilft das bei OPs Problem?

    – Melpomen

    24. Juni 2017 um 21:29 Uhr

  • Danke für diese Antwort. Obwohl es die Frage nicht direkt beantwortet, beantwortet es eine verwandte Frage zur Behandlung verschiedener Fälle auf die gleiche Weise

    – Das es

    20. Juli 2017 um 2:05 Uhr

Eine andere Variante der Antwort von OP:

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
    when (oldVersion) {
        newVersion -> return
        1 -> TODO("upgrade from v1 to v2")
        2 -> TODO("upgrade from v2 to v3")
    }
    oldVersion++
    onUpgrade(db, oldVersion, newVersion)
}

  • Wie hilft das bei OPs Problem?

    – Melpomen

    24. Juni 2017 um 21:29 Uhr

  • Danke für diese Antwort. Obwohl es die Frage nicht direkt beantwortet, beantwortet es eine verwandte Frage zur Behandlung verschiedener Fälle auf die gleiche Weise

    – Das es

    20. Juli 2017 um 2:05 Uhr

Was ist mit Kotlin DSL für die benutzerdefinierte Implementierung? Etwa dieser Ansatz:

class SwitchTest {

    @Test
    fun switchTest() {

        switch {
            case(true) {
                println("case 1")
            }
            case(true) {
                println("case 2")
            }
            case(false) {
                println("case 3")
            }
            caseBreak(true) {
                println("case 4")
            }
            case(true) {
                println("case 5")
            }
//          default { //TODO implement
//
//          }
        }
    }
}

class Switch {
    private var wasBroken: Boolean = false

    fun case(condition: Boolean = false, block: () -> Unit) {
        if (wasBroken) return
        if (condition)
            block()
    }

    fun caseBreak(condition: Boolean = false, block: () -> Unit) {
        if (condition) {
            block()
            wasBroken = true
        }
    }
}

fun switch(block: Switch.() -> Unit): Switch {
    val switch = Switch()
    switch.block()
    return switch
}

Es druckt:

case 1
case 2
case 4

UPD: Einige Refactorings und Ausgabebeispiele.

1158650cookie-checkKotlin ‘when’-Anweisung vs. Java ‘switch’

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy