La correspondance de modèle dans Kotlin est Nice et le fait qu'elle n'exécute pas la correspondance de modèle suivante est bonne dans 90% des cas d'utilisation.
Sous Android, lorsque la base de données est mise à jour, nous utilisons la propriété de commutateur Java pour passer au cas suivant si nous ne mettons pas de pause pour que le code ressemble à cela:
switch (oldVersion) {
case 1: upgradeFromV1();
case 2: upgradeFromV2();
case 3: upgradeFromV3();
}
Ainsi, si quelqu'un a une application avec la version 1 de la base de données et a manqué la version de l'application avec DB v2, il exécutera tout le code de mise à niveau nécessaire.
Convertis en Kotlin, nous obtenons un désordre comme:
when (oldVersion) {
1 -> {
upgradeFromV1()
upgradeFromV2()
upgradeFromV3()
}
2 -> {
upgradeFromV2()
upgradeFromV3()
}
3 -> {
upgradeFromV3()
}
}
Ici, nous n’avons que 3 versions, imaginez quand DB atteint la version 19: /
Quoi qu'il en soit à faire en agissant de la même manière que switch? J'ai essayé de continuer sans chance.
La solution simple mais verbeuse est la suivante:
if (oldVersion <= 1) upgradeFromV1()
if (oldVersion <= 2) upgradeFromV2()
if (oldVersion <= 3) upgradeFromV3()
Une autre solution possible avec références de fonction :
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]()
}
}
edit: Réponse originale ci-dessous. Voici ce que je fais actuellement:
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)
}
Voici une variation de la réponse @ C.A.B. a donné:
fun upgrade(oldVersion: Int) {
when (oldVersion) {
latestVersion -> return
1 -> upgradeFromV1()
2 -> upgradeFromV2()
3 -> upgradeFromV3()
}
upgrade(oldVersion + 1)
}
Que dis-tu de ça:
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()
}
}
Ajoutée:
J'aime l'idée de @lukle de définir le chemin de mise à niveau sous forme de liste. Cela permet de définir différents chemins de mise à niveau pour différentes étapes initiales. Par exemple:
Pour cela, nous devons savoir à partir de quels éléments de la liste appliquer.
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) }
}
Dans ce code, Vs peut être identique à V ou à une sorte de collection de valeurs V avec une méthode equals(other: Any?): Boolean
surchargée.
C'est tout à fait possible Citation tirée de la référence officielle: Flux de contrôle: si, quand, pour, pendant
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")
}
Donc, si la même liste de conditions est courte, vous pouvez les lister en les séparant par des virgules ou utiliser des plages telles que la condition en 1..10, comme indiqué dans d'autres réponses.
Voici un mélange des deux réponses de Bashor, avec un peu de sucre fonctionnel:
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() }
}
Une autre variante de la réponse de 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)
}
Qu'en est-il de Kotlin DSL pour une implémentation personnalisée? Quelque chose comme cette approche:
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
}
Il affiche:
case 1
case 2
case 4
UPD: Quelques refactorings et exemple de sortie.
Vous pouvez simplement utiliser pour la boucle avec quand.
for (version in oldVersion..newVersion) when (version) {
1 -> upgradeFromV1()
2 -> upgradeFromV2()
3 -> upgradeFromV3()
}