2015-06-14 95 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() }