“When”语句与Java“switch”语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30832215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:13:00  来源:igfitidea点击:

"When" statement vs Java "switch" statement

javaswitch-statementkotlin

提问by Geob-o-matic

Pattern matching in Kotlin is nice and the fact it does not execute next pattern match is good in 90% of use cases.

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

In Android, when database is updated, we use Java switch property to go on next case if we do not put a break to have code looking like that:

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

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

So if someone has an app with version 1 of the DB and missed the app version with DB v2, he will get all the needed upgrade code executed.

因此,如果某人有一个使用 DB 版本 1 的应用程序并且错过了使用 DB v2 的应用程序版本,他将执行所有需要的升级代码。

Converted to Kotlin, we get a mess like:

转换为 Kotlin 后,我们会得到类似的混乱:

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

Here we have only 3 version, imagine when DB reaches version 19 :/

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

Anyway to makes when acting in the same way than switch? I tried continue without luck.

无论如何,当以与 switch 相同的方式行事时?我尝试继续没有运气。

采纳答案by bashor

Simple but wordy solution is:

简单但冗长的解决方案是:

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

Another possible solution with 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]()
    }
}

回答by C.A.B.

How about this:

这个怎么样:

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

Added:

添加:

I like the idea by @lukleto define the upgrade path as a list. This allows to define different upgrade paths for different initial stage. For example:

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

  1. Simple fast path from released version to the latest released version
  2. Catch-up path from hot-fix version (could be few in a row), which should not be applied when going from previous full version to the next full version
  1. 从发布版本到最新发布版本的简单快速路径
  2. 热修复版本的追赶路径(可能连续几个),从上一个完整版本到下一个完整版本时不应该应用

For that we need to know from which elements of the list to apply.

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

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 this code Vs could be the same as V or some kind of collection of V values with overridden equals(other: Any?): Booleanmethod.

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

回答by Julian Delphiki

edit: Original response below. Here's what I'm currently doing:

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

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


Here's a variation on the answer @C.A.B. gave:

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

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

回答by Lukas Lechner

Here is a mix of the two answers from bashor, with a little bit of functional sugar:

这是来自 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() }
}

回答by Yarh

It is absolutly possible quote from official reference : 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")
}

So if same condition list is short, then you can list them separating by coma, or use ranges like condition in 1..10 as stated in other answers

因此,如果相同的条件列表很短,那么您可以按昏迷列出它们,或者使用其他答案中所述的 1..10 中的条件等范围

回答by arslancharyev31

Another variation of OP's answer:

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

回答by lukDeveloper

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

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

回答by Bharat Vasoya

Kotlin works with a different flow control called when.

Kotlin 使用不同的流控制,称为 when。

Your code, using it when, can be that way.

你的代码,在什么时候使用它,可以是那样的。

Obviously the code could be different, but I understand that your question is only about the use of switch.

显然代码可能会有所不同,但我知道您的问题仅与 switch 的使用有关。

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

回答by Victor Yevitchenko

What about Kotlin DSL for custom implementation? Something like this approach:

用于自定义实现的 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
}

It prints: case 1 case 2 case 4 UPD: Some refactorings and output example.

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

回答by John

You can just use for loop with when.

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

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