2015-06-14 19 views
34

Dopasowanie wzorców w Kotlin jest dobre, a fakt, że nie wykonuje następnego dopasowania do wzorca jest dobry w 90% przypadków użycia.Instrukcja "Kiedy" vs Java "switch"

W Androidzie, gdy baza danych jest aktualizowana, używamy Java przełączyć właściwość, aby przejść na następny przypadku jeśli nie włożymy przerwę mieć kod patrząc tak:

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

Więc jeśli ktoś ma app z w wersji 1 DB i opuścił wersję aplikacji z DB v2, dostanie cały potrzebny kod aktualizacji.

przeliczona na Kotlin, mamy bałagan jak:

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

Tutaj mamy tylko 3 wersji wyobrazić kiedy DB osiągnie wersję 19:/

Zresztą do marek, działając w taki sam sposób jak przełącznik? Próbowałem kontynuować bez szczęścia.

+0

Właśnie natknąłem się na https://youtrack.jetbrains.com/issue/KT-771 jakiegokolwiek obejścia wtedy? –

+1

Myślę, że statystycznie (bez dowodów, ale jestem pewien, że zespół Kotlin używał statystyk do podjęcia decyzji), że 'switch' w Javie prawie zawsze ma' break' w każdym przypadku, dlatego jest to niewygodne dla wspólnego przypadku. –

Odpowiedz

50

Proste rozwiązanie jest jednak rozwlekły:

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

Innym możliwym rozwiązaniem z 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

Świetna odpowiedź, ale można użyć rekursji zamiast wywoływania metody z pętli for dla –

10

Jak ten temat:

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

EDIT: Odpowiedź Original poniżej. Oto co mam aktualnie robi:

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

Oto wariacja na odpowiedź @ C.A.B. dał:

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

Dodaj modyfikator [tailrec] (https://kotlinlang.org/docs/reference/functions.html#tail-recursive-functions) do (rekurencyjnie nazywa się) funkcja i jesteś złoty! – Jerzyna

+0

@Jerzyna zredagowany w moim obecnym rozwiązaniu, który jest nieco ładniejszy, moim zdaniem. –

0

Tutaj jest mieszanką dwóch odpowiedzi z bashor, z odrobiną cukru funkcjonalne:

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

Jest absolutnie możliwe Cytat offisial odniesienia 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") 
} 

Więc jeśli ta sama lista warunków jest krótka, możesz wyświetlić listę rozdzielania według śpiączki lub użyć zakresów takich jak warunek w punkcie 1..10, jak podano w innych odpowiedziach

+0

Jak to pomaga w przypadku problemu z OP? – melpomene

+0

Dziękuję za tę odpowiedź. Chociaż nie odpowiada bezpośrednio na pytanie, odpowiada na podobne pytanie dotyczące obsługi różnych przypadków w ten sam sposób. – TheIT

+0

Ta odpowiedź mi pomogła :), dziękuję. – moxi

0

Inną odmianą odpowiedzi 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() } 
Powiązane problemy