"当"语句与Java"切换"语句

Geo*_*tic 55 java switch-statement kotlin

Kotlin中的模式匹配很好,并且在90%的用例中,它不执行下一个模式匹配的事实很好.

在Android中,当数据库更新时,我们使用Java开关属性继续下一个案例,如果我们不休息让代码看起来像这样:

switch (oldVersion) {
    case 1: upgradeFromV1();
    case 2: upgradeFromV2(); 
    case 3: upgradeFromV3();
}
Run Code Online (Sandbox Code Playgroud)

因此,如果有人拥有数据库版本1的应用程序而错过了使用DB v2的应用程序版本,他将获得执行所需的所有升级代码.

转换为Kotlin,我们得到一个混乱:

when (oldVersion) {
    1 -> {
        upgradeFromV1()
        upgradeFromV2()
        upgradeFromV3()
    }
    2 -> {
        upgradeFromV2()
        upgradeFromV3()
    }
    3 -> {
        upgradeFromV3()
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我们只有3个版本,想象当DB达到版本19时:/

无论如何,当以与开关相同的方式行动时?我试着继续没有运气.

bas*_*hor 64

简单而又冗长的解决方案是:

if (oldVersion <= 1) upgradeFromV1()
if (oldVersion <= 2) upgradeFromV2()
if (oldVersion <= 3) upgradeFromV3()
Run Code Online (Sandbox Code Playgroud)

用另一种可能的解决方案功能的引用:

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]()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案,但是您可以使用递归而不是从for循环中调用方法 (2认同)

Jul*_*iki 18

编辑:下面的原始回复.这是我目前正在做的事情:

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)
}
Run Code Online (Sandbox Code Playgroud)

这是@CAB给出的答案的变体:

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

  • 向(递归调用)函数添加 [tailrec](https://kotlinlang.org/docs/reference/functions.html#tail-recursive-functions) 修饰符,你就成功了! (2认同)

C.A*_*.B. 11

这个怎么样:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

添加:

我喜欢@lukle的想法,将升级路径定义为列表.这允许为不同的初始阶段定义不同的升级路径.例如:

  1. 从发布版本到最新发布版本的简单快速路径
  2. 来自热修复版本的追赶路径(可能连续几个),从以前的完整版本到下一个完整版本时不应该应用

为此,我们需要知道要应用的列表中的哪些元素.

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) }
}
Run Code Online (Sandbox Code Playgroud)

在此代码中,Vs可以与V相同或使用重写equals(other: Any?): Boolean方法的某种V值集合.


Joh*_*ohn 11

你可以只使用for循环和when。

for (version in oldVersion..newVersion) when (version) {
    1 -> upgradeFromV1()
    2 -> upgradeFromV2()
    3 -> upgradeFromV3()
}
Run Code Online (Sandbox Code Playgroud)