web-dev-qa-db-de.com

"When" -Anweisung vs Java "Switch" -Anweisung

Die Musterübereinstimmung in Kotlin ist Nizza und die Tatsache, dass die nächste Musterübereinstimmung nicht ausgeführt wird, ist in 90% der Anwendungsfälle gut.

Wenn die Datenbank aktualisiert wird, verwenden wir in Android die Java-Switch-Eigenschaft, um im nächsten Fall weiterzugehen, wenn der Code nicht 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 der gesamte erforderliche Upgrade-Code ausgeführt.

Nach Kotlin konvertiert bekommen 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 der DB die Version 19 erreicht: /

Wie auch immer, wenn man auf die gleiche Weise handelt als wechseln? Ich versuchte es ohne Glück weiter.

48
Geob-o-matic

Einfache aber wortwörtliche Lösung ist:

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

Eine andere 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]()
    }
}
59
bashor

bearbeiten: Originalantwort 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 @ C.A.B. gab:

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

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:

Mir gefällt die Idee von @lukle , den Upgrade-Pfad als Liste zu definieren. Dies ermöglicht das Definieren verschiedener Upgrade-Pfade für unterschiedliche Anfangsphasen. Zum Beispiel:

  1. Einfacher schneller Weg von der veröffentlichten Version zur neuesten veröffentlichten Version
  2. Aufholpfad von der Hotfix-Version (möglicherweise nur wenige hintereinander), der nicht angewendet werden sollte, wenn von der vorherigen Vollversion zur nächsten Vollversion übergegangen wird

Dazu müssen wir wissen, von welchen Elementen der Liste Sie sich bewerben müssen.

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 mit V oder einer Art Sammlung von V-Werten mit überschriebener equals(other: Any?): Boolean-Methode identisch sein.

11
C.A.B.

Es ist absolut möglich Zitat aus der offiziellen Referenz: Kontrollfluss: wenn, wann, 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 die gleiche Bedingungsliste kurz ist, können Sie sie getrennt nach Koma auflisten oder Bereiche wie Bedingung in 1..10 verwenden, wie in anderen Antworten angegeben 

2
Yarh

Hier ist eine Mischung aus den beiden Antworten von Bashor mit ein bisschen funktionellem Zucker:

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

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

fun upgradeFrom(oldVersion: Int) {
    upgrades.filterIndexed { index, kFunction0 -> oldVersion <= index }
            .forEach { it() }
}
0
lukle

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)
}
0
arslancharyev31

Wie sieht es mit Kotlin DSL für die kundenspezifische Implementierung aus? So etwas wie 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.

0

Sie können for-Schleife einfach mit wann verwenden.

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