Использование предложения 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 предложение привлекательно, но не работает, как я ожидал для такого рода сравнения.

3 ответов


даже гибкий язык, такой как Kotlin, не имеет "элегантного" / сухого решения для каждого случая.

вы можете написать что-то вроде:

when (foo) {
    in 0 .. Int.MAX_VALUE -> doSomethingWhenPositive()
    0    -> doSomethingWhenZero()
    else -> doSomethingWhenNegative()
}

но тогда вы зависите от типа переменной.

Я считаю, что следующая форма является наиболее идиоматичной в Котлине:

when {
    foo > 0  -> doSomethingWhenPositive()
    foo == 0 -> doSomethingWhenZero()
    else     -> doSomethingWhenNegative()
}

да... существует некоторое (минимальное) дублирование кода.

некоторые языки (Ruby?!) пытался предоставить uber-элегантную форму для любого случая - но есть компромисс: язык становится более сложным и трудным для программиста, чтобы знать от начала до конца.

мои 2 цента...


The грамматика на when условие следующим образом:

whenCondition (used by whenEntry)
  : expression
  : ("in" | "!in") expression
  : ("is" | "!is") type
  ;

это означает, что вы можете только использовать is или in как особые случаи, которые не должны быть полным выражением; все остальное должно быть нормальным выражением. С > 0 не является допустимым выражением, которое не будет компилироваться.

кроме того, диапазоны закрыты в Котлине, поэтому вы не можете уйти, пытаясь использовать неограниченный диапазон.

вместо этого вы должны использовать when заявление с полным выражением, как в вашем примере:

when {
    foo > 0 -> doSomethingWhenPositive()
    foo < 0 -> doSomethingWhenNegative()
    else -> doSomethingWhenZero()
}

или же:

when {
    foo < 0 -> doSomethingWhenNegative()
    foo == 0 -> doSomethingWhenZero()        
    foo > 0 -> doSomethingWhenPositive()        
}

что может быть более читаемым.


вы хотите, чтобы ваш код был элегантным, так зачем оставаться на 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.
}

если вы счастливы, вы можете переименовать