Kotlin当具有大范围的语句在给定可为null的Int时冻结



我使用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为null时:

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不可为null或检查null一样,但我肯定遗漏了一些东西:

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

  • 如果它真的在该范围内的每个值中迭代,为什么对于可为null的Ints它只那么慢?(就这一点而言,为什么这在任何地方都没有记录下来,因为这似乎应该是一个相当常见的用例?(

  • 有没有更易读的方法可以做到这一点?

如果有这样的东西,我会很高兴的:

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

但这似乎是不可能的,事实上,寻找这一点正是我最初使用靶场的原因。

如果有任何建议,我将不胜感激。谢谢

如果我们看到IntRange的实现,则没有定义可为null的Intin运算符,因此它返回到Iterable<T>.contains()


对于Ints-O(1(

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

对于Int?s-O(n(

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
} 

这将确定给定的可为null的Int是否在O(1(时间中的某个IntRange中。

最新更新