为什么 Kotlin 中没有 ClosedRange IN ClosedRange 运算符?
Why is there no ClosedRange IN ClosedRange Operator in Kotlin?
让val a, b, x, y: LocalDate
.
那么 a..b in x..y
不是有效的表达式:ClosedRange in ClosedRange
未定义。
但是,(a..b).toRange() in (x..y).toRange()
确实有效,因为 Range in Range
已定义。
除了 b < a
或 y < x
因为 ranges
不能为负数。
请注意,我正在为 Android 开发,这是 .toRange()
的来源:androidx.core/core-ktx
3个问题出现
- 这是 android / kotlin 团队的疏忽吗?
- 这是故意的吗? (例如,由于一些不直观的行为)
- 万一这是一个深思熟虑的决定:如何最好地规避它?
免责声明:我不是 Android 开发人员,也没有使用 androidx.core 的经验,所以请对我的回答持保留态度。
所以假设你可以 a..b
创建一个 ClosedRange(这在 Kotlin stdlib 中默认不可用,但也许 core-ktx 定义了它自己的扩展),根据 Kotlin documentation, x in y
gets translated to y.contains(x)
. Now, ClosedRange
定义了一些 contains
方法,但其中 none 接受另一个 ClosedRange
作为参数,因此你的错误。
现在,显然 Android stdlib 定义了它自己的 Range
, which is unrelated to Kotlin's ClosedRange
(as one does not extend the other). However, core-ktx
defines a function to transform a ClosedRange
to a Range
, and that function is .toRange()
. In addition to that, Range
defines a contains(Range)
方法概念,这就是第二个示例编译正确的原因。
总结一下:Kotlin 不允许 (1) 默认创建日期范围,以及 (2) 检查一个范围是否完全包含在另一个范围内。但是,您可以轻松克服 (1) 通过创建自己的函数来为日期创建 ClosedRange
(通过创建 rangeTo
extension function),以及 (2) 通过创建自己的 contains(Range)
函数。
回到为什么 a..b
在使用 core-ktx
时有效,我找不到满意的答案。该库包含一个 rangeTo
扩展函数,用于创建任何 Comparable
范围之外的范围(并且 LocalDate
是一个 Comparable
),但是该函数 returns Range
,而不是 ClosedRange
,所以我不确定为什么 a..b in x..y
首先不起作用。
ClosedRange 是 Kotlin 标准库的一部分。范围是 Android 的 SDK 的一部分。这两个库是由不同的公司制作的,并且在制作时考虑到了不同的目标,因此您不一定可以将其称为疏忽。也许 Kotlin 开发人员认为一个范围在另一个范围内的含义可能不明确,而 Android 开发人员则没有。或者,也许 Kotlin 开发人员对哪些功能足够有用以包含在标准库中有更高的标准。
两个 classes 之间的一个区别是 Android Range class 禁止起始值高于较低值的范围,但 Kotlin ClosedRange 允许。这使得包含另一个 ClosedRange 的概念比 Ranges 更加模糊。负方向 ClosedRange 位于另一个 ClosedRange 中意味着什么?它是空的,但它有一个跨度。
我不确定你所说的绕过它是什么意思。如果需要,您可以为 ClosedRange 定义自己的扩展函数,其行为取决于您希望如何解释包含的空范围的含义。
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
other.start in this && other.endInclusive in this
// or
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
other.isEmpty() || (other.start in this && other.endInclusive in this)
// or
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
(other.isEmpty() && (other.start in this || other.endInclusive in this)) ||
(other.start in this && other.endInclusive in this)
让val a, b, x, y: LocalDate
.
那么 a..b in x..y
不是有效的表达式:ClosedRange in ClosedRange
未定义。
但是,(a..b).toRange() in (x..y).toRange()
确实有效,因为 Range in Range
已定义。
除了 b < a
或 y < x
因为 ranges
不能为负数。
请注意,我正在为 Android 开发,这是 .toRange()
的来源:androidx.core/core-ktx
3个问题出现
- 这是 android / kotlin 团队的疏忽吗?
- 这是故意的吗? (例如,由于一些不直观的行为)
- 万一这是一个深思熟虑的决定:如何最好地规避它?
免责声明:我不是 Android 开发人员,也没有使用 androidx.core 的经验,所以请对我的回答持保留态度。
所以假设你可以 a..b
创建一个 ClosedRange(这在 Kotlin stdlib 中默认不可用,但也许 core-ktx 定义了它自己的扩展),根据 Kotlin documentation, x in y
gets translated to y.contains(x)
. Now, ClosedRange
定义了一些 contains
方法,但其中 none 接受另一个 ClosedRange
作为参数,因此你的错误。
现在,显然 Android stdlib 定义了它自己的 Range
, which is unrelated to Kotlin's ClosedRange
(as one does not extend the other). However, core-ktx
defines a function to transform a ClosedRange
to a Range
, and that function is .toRange()
. In addition to that, Range
defines a contains(Range)
方法概念,这就是第二个示例编译正确的原因。
总结一下:Kotlin 不允许 (1) 默认创建日期范围,以及 (2) 检查一个范围是否完全包含在另一个范围内。但是,您可以轻松克服 (1) 通过创建自己的函数来为日期创建 ClosedRange
(通过创建 rangeTo
extension function),以及 (2) 通过创建自己的 contains(Range)
函数。
回到为什么 a..b
在使用 core-ktx
时有效,我找不到满意的答案。该库包含一个 rangeTo
扩展函数,用于创建任何 Comparable
范围之外的范围(并且 LocalDate
是一个 Comparable
),但是该函数 returns Range
,而不是 ClosedRange
,所以我不确定为什么 a..b in x..y
首先不起作用。
ClosedRange 是 Kotlin 标准库的一部分。范围是 Android 的 SDK 的一部分。这两个库是由不同的公司制作的,并且在制作时考虑到了不同的目标,因此您不一定可以将其称为疏忽。也许 Kotlin 开发人员认为一个范围在另一个范围内的含义可能不明确,而 Android 开发人员则没有。或者,也许 Kotlin 开发人员对哪些功能足够有用以包含在标准库中有更高的标准。
两个 classes 之间的一个区别是 Android Range class 禁止起始值高于较低值的范围,但 Kotlin ClosedRange 允许。这使得包含另一个 ClosedRange 的概念比 Ranges 更加模糊。负方向 ClosedRange 位于另一个 ClosedRange 中意味着什么?它是空的,但它有一个跨度。
我不确定你所说的绕过它是什么意思。如果需要,您可以为 ClosedRange 定义自己的扩展函数,其行为取决于您希望如何解释包含的空范围的含义。
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
other.start in this && other.endInclusive in this
// or
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
other.isEmpty() || (other.start in this && other.endInclusive in this)
// or
operator fun <T: Comparable<T>> ClosedRange<in T>.contains(other: ClosedRange<out T>): Boolean =
(other.isEmpty() && (other.start in this || other.endInclusive in this)) ||
(other.start in this && other.endInclusive in this)