给定可为null的Int时,Kotlin when大范围语句冻结

时间:2018-07-20 00:18:43

标签: android kotlin

我正在使用when语句来检查变量是否在相当大的范围内。

为简单起见,我的代码如下:

val lowRange = Int.MIN_VALUE..0
val mediumRange = 1..999_999
//...

val valToCheck = 1_000_000

when (valToCheck) {
    in lowRange -> { doSomething() }
    in mediumRange -> { doSomethingElse() }
    //...
    else -> { handleTooHighOrNull() }
}

这很好用;但是,当我使valToCheck可为空时:

val lowRange = Int.MIN_VALUE..0
val mediumRange = 1..999_999
//...

val valToCheck = if(someCondition) { 1_000_000 } else { null }

when (valToCheck) {
    in lowRange -> { doSomething() }
    in mediumRange -> { doSomethingElse() }
    //...
    else -> { handleTooHighOrNull() }
}

我的应用程序完全死机了。

减小范围的大小确实解决了此问题,就像使valToCheck不可为空或检查空值作为第一种情况一样,但我必须在这里缺少某些内容:

  • 为什么会这样? in运算符真的只是遍历范围内的每个数字并将其与给定值进行比较吗?

  • 如果实际上要遍历范围内的每个值,为什么对于可为null的Int而言,它这么慢? (为此,为什么没有在任何地方对此进行记录,因为这似乎是一个相当普遍的用例?)

  • 是否有更易读的方法来执行此操作?

如果有类似的东西,我会喜欢的:

when(valToCheck) {
    < 0 -> { doSomething() }
    < 500 -> { doSomethingElse() }
    //...
    else -> { handleTooHighOrNull() }
}

但这似乎是不可能的,实际上,搜索该内容是我首先使用范围的原因。

非常感谢您提出任何建议。谢谢!

1 个答案:

答案 0 :(得分:6)

如果我们看到IntRange的实现,则未定义可空in的{​​{1}}运算符-因此它会退回到Int


对于Iterable<T>.contains()秒- O(1)

Int

对于public class IntRange(start: Int, endInclusive: Int) : IntProgression(start, endInclusive, 1), ClosedRange<Int> { ... override fun contains(value: Int): Boolean = first <= value && value <= last ... } 秒- O(n)

Int?

您可以通过以下扩展功能来解决此问题:

public operator fun <@kotlin.internal.OnlyInputTypes T> Iterable<T>.contains(element: T): Boolean {
    if (this is Collection)
        return contains(element)
    return indexOf(element) >= 0
}

这将确定给定的可空operator fun IntRange.contains(value: Int?): Boolean { return if (value != null) { first <= value && value <= last } else false } 是否在O(1)时间的某个Int中。