Kotlin 'when' 语句 vs Java 'switch'
Kotlin 'when' statement vs Java 'switch'
Kotlin 中的模式匹配很好,而且它不执行下一个模式匹配这一事实在 90% 的用例中都很好。
在 Android 中,当数据库更新时,如果我们不中断代码,我们使用 Java 开关 属性 继续下一个案例:
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()
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]()
}
}
这个怎么样:
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()
}
}
已添加:
我喜欢 将升级路径定义为列表的想法。这允许为不同的初始阶段定义不同的升级路径。例如:
- 从发布版本到最新发布版本的简单快速路径
- 热修复版本的追赶路径(可能连续几个),从以前的完整版本到下一个完整版本时不应应用
为此,我们需要知道要应用列表中的哪些元素。
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 值的集合。
编辑:下面是原始回复。这是我目前正在做的事情:
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)
}
这里是 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() }
}
绝对有可能
引用自官方参考: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")
}
因此,如果相同的条件列表很短,那么您可以将它们以逗号分隔列出,或者使用其他答案中所述的范围,例如 1..10 中的条件
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)
}
val orders = arrayListOf(
{ upgradeFromV1()},
{ upgradeFromV2()},
{ upgradeFromV3()}
)
orders.drop(oldVersion).forEach { it() }
Kotlin 使用称为 when 的不同流程控制。
你的代码,什么时候用,可以这样。
显然代码可能不同,但我知道你的问题只是关于 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);
}
自定义实现的 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:一些重构和输出示例。
你可以在 when 中使用 for 循环。
for (version in oldVersion..newVersion) when (version) {
1 -> upgradeFromV1()
2 -> upgradeFromV2()
3 -> upgradeFromV3()
}
如果您不关心 运行 这些功能的顺序,您可以制作自己的伪开关,例如:
function PretendSwitch() {
if(oldVersion>3) return
upgradeFromV3();
if(oldVersion==3) return
upgradeFromV2()
if(oldVersion==2) return
upgradeFromV1()
if(oldVersion==1) return
}
没有什么比使用开关更干净的了。不幸的是,Kotlin 缺少 switch 语句,因此无法优雅地执行此操作。
val 旧版本 = 6
val newVersion = 10
for (version in oldVersion until newVersion) {
when (version) {
1 -> upgradeFromV1()
2 -> upgradeFromV2()
3 -> upgradeFromV3()
4 -> upgradeFromV4()
5 -> upgradeFromV5()
6 -> upgradeFromV6()
7 -> upgradeFromV7()
8 -> upgradeFromV8()
9 -> upgradeFromV9()
}
println("~~~")
}
Kotlin 中的模式匹配很好,而且它不执行下一个模式匹配这一事实在 90% 的用例中都很好。
在 Android 中,当数据库更新时,如果我们不中断代码,我们使用 Java 开关 属性 继续下一个案例:
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()
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]()
}
}
这个怎么样:
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()
}
}
已添加:
我喜欢
- 从发布版本到最新发布版本的简单快速路径
- 热修复版本的追赶路径(可能连续几个),从以前的完整版本到下一个完整版本时不应应用
为此,我们需要知道要应用列表中的哪些元素。
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 值的集合。
编辑:下面是原始回复。这是我目前正在做的事情:
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)
}
这里是 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() }
}
绝对有可能 引用自官方参考: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")
}
因此,如果相同的条件列表很短,那么您可以将它们以逗号分隔列出,或者使用其他答案中所述的范围,例如 1..10 中的条件
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)
}
val orders = arrayListOf(
{ upgradeFromV1()},
{ upgradeFromV2()},
{ upgradeFromV3()}
)
orders.drop(oldVersion).forEach { it() }
Kotlin 使用称为 when 的不同流程控制。
你的代码,什么时候用,可以这样。
显然代码可能不同,但我知道你的问题只是关于 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);
}
自定义实现的 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:一些重构和输出示例。
你可以在 when 中使用 for 循环。
for (version in oldVersion..newVersion) when (version) {
1 -> upgradeFromV1()
2 -> upgradeFromV2()
3 -> upgradeFromV3()
}
如果您不关心 运行 这些功能的顺序,您可以制作自己的伪开关,例如:
function PretendSwitch() {
if(oldVersion>3) return
upgradeFromV3();
if(oldVersion==3) return
upgradeFromV2()
if(oldVersion==2) return
upgradeFromV1()
if(oldVersion==1) return
}
没有什么比使用开关更干净的了。不幸的是,Kotlin 缺少 switch 语句,因此无法优雅地执行此操作。
val 旧版本 = 6 val newVersion = 10
for (version in oldVersion until newVersion) {
when (version) {
1 -> upgradeFromV1()
2 -> upgradeFromV2()
3 -> upgradeFromV3()
4 -> upgradeFromV4()
5 -> upgradeFromV5()
6 -> upgradeFromV6()
7 -> upgradeFromV7()
8 -> upgradeFromV8()
9 -> upgradeFromV9()
}
println("~~~")
}