使用Kotlin WHEN子句进行<,<=,> =,>比较
我试图使用WHEN
子句与>
或<
比较。
这不会编译。 在比较中使用普通的布尔运算符(<= =,> =>)来实现这一点吗?
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
子句是有吸引力的,但是并不像我预期的那样。
即使是像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分钱…
when
条件的语法如下:
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() }
这可能更具可读性。
你想要你的代码优雅,所以为什么留在表达式。 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。