Kotlinのパターンマッチングは優れており、次のパターンマッチングを実行しないという事実は、ユースケースの90%で良好です。
Androidでは、データベースが更新されたときに、Java switchプロパティを使用して、次のケースに進むために、次のようなコードにブレークを入れない場合:
switch (oldVersion) {
case 1: upgradeFromV1();
case 2: upgradeFromV2();
case 3: upgradeFromV3();
}
したがって、誰かがDBのバージョン1のアプリを使用していて、DB v2のアプリのバージョンを見逃した場合、必要なすべてのアップグレードコードが実行されます。
Kotlinに変換すると、次のような混乱が生じます。
when (oldVersion) {
1 -> {
upgradeFromV1()
upgradeFromV2()
upgradeFromV3()
}
2 -> {
upgradeFromV2()
upgradeFromV3()
}
3 -> {
upgradeFromV3()
}
}
ここには3つのバージョンしかありません。DBがバージョン19に達すると想像してください:/
とにかくスイッチよりも同じように行動するときに作る?私は運なしで続けようとしました。
シンプルだが冗長な解決策は次のとおりです。
if (oldVersion <= 1) upgradeFromV1()
if (oldVersion <= 2) upgradeFromV2()
if (oldVersion <= 3) upgradeFromV3()
関数参照 を使用した別の可能な解決策:
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]()
}
}
編集:以下の元の応答。私が現在していることは次のとおりです。
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)
}
これはどう:
_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 のアイデアが気に入っています。これにより、初期段階ごとに異なるアップグレードパスを定義できます。例えば:
そのためには、リストのどの要素から適用するかを知る必要があります。
_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値のコレクションのいずれかです。
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)
}
公式リファレンスから絶対に可能な引用です: 制御フロー: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の条件のような範囲を使用できます
Forループはwhenで使用できます。
for (version in oldVersion..newVersion) when (version) {
1 -> upgradeFromV1()
2 -> upgradeFromV2()
3 -> upgradeFromV3()
}
以下は、bashorからの2つの回答と、機能的な砂糖を少し混ぜたものです。
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() }
}
カスタム実装用の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:いくつかのリファクタリングと出力例。