我正在使用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() }
}
但这似乎是不可能的,实际上,搜索该内容是我首先使用范围的原因。
非常感谢您提出任何建议。谢谢!
答案 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
中。