操作符 …<
..<
操作符是 Kotlin 在 1.7.20 版本中引入的不包含尾部元素的左闭右开区间操作符。之前我们使用的比较多的操作符可能是 ..
和 until
,两者均表示区间,前者是闭区间,后者则表示不包含末端元素的左闭右开区间。
@OptIn(ExperimentalStdlibApi::class)
fun main() {
val myRange = 0.0..<10.0 // [0.0, 10.0)
val yourRange = 0..10 // [0, 10]
val herRange = 0 until 10 // [0, 9]
}
IDEA 会通过数学符号给出明确的范围提示。
为什么需要 …< ?
针对整形, ..
和 until
可以处理闭区间和左闭右开区间。
fun main() {
val yourRange = 0..10 // [0, 10]
val herRange = 0 until 10 // [0, 9]
println(0 in yourRange) // true
println(10 in yourRange) // true
println(11 in yourRange) // false
println(0 in herRange) // true
println(10 in herRange) // false
println(11 in herRange) // false
}
但是针对浮点型,之前我们只能使用..
操作符处理闭区间,但是对应 until
的左闭右开区间却无法直接实现。
fun main() {
val yourRange = 0.0..10.0 // [0.0, 10.0]
val herRange = 0.0 until 10.0 // Compile Error
println(0.0 in yourRange) // true
println(10.0 in yourRange) // true
println(11.0 in yourRange) // false
}
没有 ..<
操作符之前,要实现**[0.0,10.0)** 区间,只能使用近似的方法 nextDown
,但是依然会有误差。
import kotlin.math.nextDown
fun main() {
println(0.0..10.0.nextDown())
// 0.0..9.999999999999998
println(0.0..0.5.nextDown())
// 0.0..0.49999999999999994
}
所以,我们需要 rangeUntil
操作符 ..<
帮助我们解决这个问题。
如何使用?
The new operator is Experimental, and it has limited support in the IDE.
- 启用
-language-version 1.8
编译选项。如果是build.gradle.kts
文件,如下:
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
languageVersion = "1.8"
}
- 添加注解
@OptIn(ExperimentalStdlibApi::class)
。当然 IDEA 会给予开发者提示。
示例
- 浮点数半开半闭区间
@OptIn(ExperimentalStdlibApi::class)
fun main() {
val myRange = 0.0..<10.0
println(0.0 in myRange) // true
println(9.99999999999999 in myRange) // true
println(10.0 in myRange) // false
}
- 时间半开半闭区间
import java.sql.Date
import java.time.LocalDate
@OptIn(ExperimentalStdlibApi::class)
fun main() {
val dayOf2022 = LocalDate.of(2022, 1, 1)
val dayOf2023 = LocalDate.of(2023, 1, 1)
println(dayOf2022..<dayOf2023)
// 2022-01-01..<2023-01-01
val start = Date.valueOf("2017-01-01")
val end = Date.valueOf("2017-12-31")
val range = start..<end
println(Date.valueOf("2017-05-27") in range) // true
println(Date.valueOf("2017-12-31") in range) // false
println(Date.valueOf("2018-01-01") in range) // false
}
为什么可以实现时间类型的半开半闭区间呢?看下源码即可。
@SinceKotlin("1.7")
@ExperimentalStdlibApi
public operator fun <T : Comparable<T>> T.rangeUntil(that: T): OpenEndRange<T> = ComparableOpenEndRange(this, that)
任何实现 Comparable
接口的类都可以使用 ..<
运算符而无需显式定义其功能。
本文部分内容译自:https://medium.com/codex/theres-a-new-operator-in-kotlin-f9ad86dfbbb5