我正在尝试将WHEN
子句用于>
或<
比较。
这不编译。有没有办法在比较中使用普通的布尔运算符集(&lt;&lt;&lt; =,&gt; =&gt;)来启用它?
val foo = 2
// doesn't compile
when (foo) {
> 0 -> doSomethingWhenPositive()
0 -> doSomethingWhenZero()
< 0 -> doSomethingWhenNegative()
}
我试图找到一个无限范围比较,但也无法使这项工作?是否可以将其写为无界范围?
// trying to get an unbounded range - doesn't compile
when (foo) {
in 1.. -> doSomethingWhenPositive()
else -> doSomethingElse()
}
你可以将整个表达式放在第二部分,这是好的,但似乎是不必要的重复。至少它编译和工作。
when {
foo > 0 -> doSomethingWhenPositive()
foo < 0 -> doSomethingWhenNegative()
else -> doSomethingWhenZero()
}
但我不确定这比我们多年来一直在做的if-else替代方案更简单。类似的东西:
if ( foo > 0 ) {
doSomethingWhenPositive()
}
else if (foo < 0) {
doSomethingWhenNegative()
}
else {
doSomethingWhenZero()
}
当然,现实问题比上面的问题更复杂,WHEN
条款很有吸引力,但不能像我期望的那样进行比较。
答案 0 :(得分:9)
即使像Kotlin这样灵活的语言也没有针对每个案例的“优雅”/ DRY解决方案。
你可以这样写:
when (foo) {
in 0 .. Int.MAX_VALUE -> doSomethingWhenPositive()
0 -> doSomethingWhenZero()
else -> doSomethingWhenNegative()
}
但是你依赖变量类型。
我认为以下形式是Kotlin中最惯用的形式:
when {
foo > 0 -> doSomethingWhenPositive()
foo == 0 -> doSomethingWhenZero()
else -> doSomethingWhenNegative()
}
是的......有一些(最小的)代码重复。
有些语言(Ruby ?!)试图为任何情况提供一种超级优雅的形式 - 但有一个权衡:语言变得更复杂,更难以让程序员知道端到端。
我的2美分......
答案 1 :(得分:5)
when
条件的grammar如下:
whenCondition (used by whenEntry)
: expression
: ("in" | "!in") expression
: ("is" | "!is") type
;
这意味着您只能将is
或in
用作不必是完整表达式的特殊情况;其他一切都必须是正常的表达。由于> 0
不是有效表达式,因此无法编译。
此外,范围在Kotlin中已关闭,因此您无法逃避尝试使用无限范围。
相反,您应该将when
语句与完整表达式一起使用,如示例所示:
when {
foo > 0 -> doSomethingWhenPositive()
foo < 0 -> doSomethingWhenNegative()
else -> doSomethingWhenZero()
}
或者:
when {
foo < 0 -> doSomethingWhenNegative()
foo == 0 -> doSomethingWhenZero()
foo > 0 -> doSomethingWhenPositive()
}
可能更具可读性。
答案 2 :(得分:1)
您希望代码优雅,为什么要留在when
表达式上。 Kotlin足够灵活,可以使用扩展来构建一个新的。
首先,我们应声明我们只能在此处传递Comparable<T>
,因为您必须比较该值。
然后,我们有了我们的框架:
fun <T: Comparable<T>> case(target: T, tester: Tester<T>.() -> Unit) {
val test = Tester(target)
test.tester()
test.funFiltered?.invoke() ?: return
}
class Tester<T : Comparable<T>>(val it: T) {
var funFiltered: (() -> Unit)? = null
infix operator fun Boolean.minus(block: () -> Unit) {
if (this && funFiltered == null) funFiltered = block
}
fun lt(arg: T) = it < arg
fun gt(arg: T) = it > arg
fun ge(arg: T) = it >= arg
fun le(arg: T) = it <= arg
fun eq(arg: T) = it == arg
fun ne(arg: T) = it != arg
fun inside(arg: Collection<T>) = it in arg
fun inside(arg: String) = it as String in arg
fun outside(arg: Collection<T>) = it !in arg
fun outside(arg: String) = it as String !in arg
}
之后我们可以拥有优雅的代码,如:
case("g") {
(it is String) - { println("hello") } // normal comparison, like `is`
outside("gg") - { println("gg again") } // invoking the contains method
}
case(233) {
lt(500) - { println("less than 500!") }
// etc.
}
如果您满意,可以将minus
功能重命名为compareTo
并返回0.这样,您可以将-
替换为=>
,看起来像scala。
答案 3 :(得分:0)
我们可以使用let
来实现此行为。
response.code().let {
when {
it == 200 -> handleSuccess()
it == 401 -> handleUnauthorisedError()
it >= 500 -> handleInternalServerError()
else -> handleOtherErrors()
}
}
希望这会有所帮助
答案 4 :(得分:-1)
我发现了一种小技巧,可以帮助您将大于,小于或任何其他表达式与其他表达式混合。 简单来说,Kotlin中的when语句查看“ case”,如果它是一个范围,它将查看变量是否在该范围内,但是如果不是,它将查看该案例是否属于同一类型变量,如果不是,则会出现语法错误。因此,要解决此问题,您可以执行以下操作:
when (foo) {
if(foo > 0) foo else 5 /*or any other out-of-range value*/ -> doSomethingWhenPositive()
in -10000..0 -> doSomethingWhenBetweenNegativeTenKAndZero()
if(foo < -10000) foo else -11000 -> doSomethingWhenNegative()
}
如您所见,这利用了Kotlin中的所有内容都是表达式的事实。因此,IMO,在此功能被添加到语言中之前,这是一个非常好的解决方案。