"当"声明与Java"开关"声明

时间:2015-06-14 17:09:54

标签: java switch-statement kotlin

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

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

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

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

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

Col[2]

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

无论如何以与开关相同的方式行事?我试着继续没有运气。

12 个答案:

答案 0 :(得分:61)

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

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

function references的另一种可能解决方案:

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]()
    }
}

答案 1 :(得分:17)

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

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

这是答案@ C.A.B的变体。得到:

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

答案 2 :(得分: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()
    }
}

添加了:

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

  1. 从发布版本到最新发布版本的简单快速路径
  2. 来自热修复版本的追赶路径(可能连续几次),从以前的完整版本转到下一个完整版本时不应该应用
  3. 为此,我们需要知道要应用的列表中的哪些元素。

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

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

答案 3 :(得分:2)

绝对可能 官方参考引用:Control Flow: if, when, for, while

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")
}

因此,如果相同的条件列表很短,那么您可以将它们列为以逗号分隔,或者使用范围如1..10中的条件,如其他答案中所述

答案 4 :(得分:1)

您可以只使用for循环与when。

if (!file_exists($_FILES['img']['tmp_name']) || !is_uploaded_file($_FILES['img']['tmp_name'])) {
  $upload = 1;
  echo "upload 1";
} else {
  $upload = 0;
  echo "upload 0";
}

答案 5 :(得分:0)

以下是来自bashor的两个答案的混合,以及一些功能性的糖:

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() }
}

答案 6 :(得分:0)

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

答案 7 :(得分:0)

用于自定义实现的Kotlin DSL呢?类似于这种方法:

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
}

它打印: case 1 case 2 case 4 UPD:一些重构和输出示例。

答案 8 :(得分:0)

如果你不关心你运行这些函数的顺序,你可以自己做一个伪开关,比如:

function PretendSwitch() {
  if(oldVersion>3) return
  upgradeFromV3();
  if(oldVersion==3) return
  upgradeFromV2()
  if(oldVersion==2) return
  upgradeFromV1()
  if(oldVersion==1) return
}

没有什么比使用开关更干净的了。不幸的是,Kotlin 缺少 switch 语句,因此无法优雅地执行此操作。

答案 9 :(得分:0)

val oldVersion = 6 val newVersion = 10

for (version in oldVersion until newVersion) {
    when (version) {
        1 -> upgradeFromV1()
        2 -> upgradeFromV2()
        3 -> upgradeFromV3()
        4 -> upgradeFromV4()
        5 -> upgradeFromV5()
        6 -> upgradeFromV6()
        7 -> upgradeFromV7()
        8 -> upgradeFromV8()
        9 -> upgradeFromV9()
    }
    println("~~~")
}

答案 10 :(得分:-1)

val orders = arrayListOf(
            { upgradeFromV1()},
            { upgradeFromV2()},
            { upgradeFromV3()}
)

orders.drop(oldVersion).forEach { it() }

答案 11 :(得分:-3)

Kotlin使用不同的流量控制来调用。

您的代码在使用时可以是这样的。

显然代码可能不同,但我知道你的问题只是关于交换机的使用。

fun main(args: Array<String>) {
val month = 8

val monthString = when(month) {
    1 -> "Janeiro"
    2 -> "February"
    3 -> "March"
    4 -> "April"
    5 -> "May"
    6 -> "June"
    7 -> "July"
    8 -> "August"
    9 -> "September"
    12 -> "October"
    11 -> "November"
    10 -> "December"
    else -> "Invalid month"      
}

println(monthString);
}