2015-06-14 92 views
34

Kotlin中的模式匹配很好,而且它不执行下一次模式匹配的事实在90%的用例中很好。“When”声明与Java“switch”声明

在Android中,当数据库被更新时,我们使用Java切换属性去下一个情况下,如果我们不把休息有代码看这样的:

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

因此,如果有人有一个应用程序版本1的数据库并且错过了使用数据库v2的应用程序版本,他将获得所有必需的升级代码。

转换为科特林,我们得到了一个烂摊子,如:

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

这里,我们只有3版本,想象一下当DB达到19版:以同样的方式不是演戏的时候/

反正品牌开关?我尝试继续没有运气。

+0

只是偶然在https://youtrack.jetbrains.com/issue/KT-771那么什么解决办法? –

+1

我认为在统计学上(没有证据,但我确定Kotlin团队使用统计数据来判断)Java中的“switch”几乎总是有一个“break”,因此这对常见情况来说很不方便。 –

回答

50

简单而罗嗦的解决方案是:

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

伟大的答案,但你可以使用递归而不是从循环调用方法 –

10

如何:

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

编辑:下面原始响应。下面是目前我在做什么:

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

添加一个[tailrec](https://kotlinlang.org/docs/reference/functions.html#tail-recursive-functions)修饰符(递归地所谓的)功能,你是金! – Jerzyna

+0

@Jerzyna在我目前的解决方案中进行编辑,在我看来,它稍微好一些。 –

0

这里是bashor两个答案,但具有的功能糖一点点:从offisial参考

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

这是绝对可能的 报价https://kotlinlang.org/docs/reference/control-flow.html

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中的条件,如其他答案中所述

+0

这对OP的问题有什么帮助? – melpomene

+0

感谢您的回答。虽然它不直接回答这个问题,但它确实回答了以相同方式处理各种情况的相关问题。 – TheIT

+0

此答案帮助了我:),谢谢。 – moxi

0

OP的回答的另一个变化:

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { 
    when (oldVersion) { 
     newVersion -> return 
     1 -> TODO("upgrade from v1") 
     2 -> TODO("upgrade from v2") 
    } 
    onUpgrade(db, oldVersion,newVersion) 
} 
-1
val orders = arrayListOf(
      { upgradeFromV1()}, 
      { upgradeFromV2()}, 
      { upgradeFromV3()} 
) 

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