Kotlin:相等比较似乎可以为空,但大于比较则不然
Kotlin: equal comparison seems OK on nullable, but greater than comparison is not
我是 Kotlin 新手。我正在学习一个教程,其中 GUI 部分涉及以下代码片段:
sampleList.addMouseListener(object: MouseAdapter() {
override fun mouseClicked(mouseEvent: MouseEvent?) {
if (mouseEvent?.clickCount == 2) {
launchSelectedSample()
}
}
})
mouseEvent
是 显然是 可空的 。在以前的编码经验中,我习惯于将 mouseEvent?.clickCount == 2
之类的行更改为 mouseEvent?.clickCount > 1
(或者可能是 >=2
), 以确保没有极端情况 其中点击发生得如此之快,以至于它从 1 跳到 3,或类似的东西。
所以,我将此代码切换为:
sampleList.addMouseListener(object: MouseAdapter() {
override fun mouseClicked(mouseEvent: MouseEvent?) {
if (mouseEvent?.clickCount >= 2) {
launchSelectedSample()
}
}
})
进行切换(将 ==2
更改为 >=2
)后,我从 IntelliJ 收到以下错误:
Operator call corresponds to a dot-qualified call 'mouseEvent?.clickCount.compareTo(2)' which is not allowed on a nullable receiver 'mouseEvent?.clickCount'.
这给我提出了 2 个问题:
- 为什么
==2
可以正常工作,而>=2
却不行? (我尝试了 >1
,它给出了与 >=2
相同的错误。)
- 处理极端情况的正确方法是什么,我真正想要的是大于 1 的值?
我喜欢确保 null
s 在运行时不会搞砸的想法,但我有点希望 Kotlin 完全摆脱 null
值并做一些像 Rust 或 Haskell。 (不过,到目前为止,我确实喜欢我所看到的 Kotlin。)
当 mouseEvent == null
时,您期望 mouseEvent?.clickCount >= 2
有什么行为?
您可以使用 elvis (?:
) 运算符将 mouseEvent?.clickCount
转换为 NotNull:
val clickCount = mouseEvent?.clickCount ?: 0
if (clickCount >= 2) {
launchSelectedSample()
}
在这种情况下,如果 mouseEvent
为 null
,则 mouseEvent?.clickCount
将为 0
==2
有效是因为 mouseEvent?.clickCount
被 Kotlin 视为 null
并且比较 null == 2
与 null >= 2
不同是正确的
如您所见,Kotlin 的等式运算符(==
和 !=
)可以处理空值,而顺序比较运算符(<
、<=
、>
, >=
) 不能。
这可能是因为对于空值,意味着 什么相等性检查是显而易见的 — 两个空值显然相等,非空值永远不应该等于空值 — 而事实并非如此完全清楚它对订单比较意味着什么。 (如果 null 不 < 0,是否意味着 null >= 0?如果不是,则您不再有明确定义的顺序。)
这体现在实现上:Any
有一个equals()
方法,表示可以检查所有对象是否相等。 (Kotlin 的 documentation makes it explicit, as does that for the underlying Java method,非 null 对象绝不能等于 null。)Kotlin 对 ==
和 !=
运算符的实现明确检查空值。 (a == b
转换为您必须在 Java 中拼出的内容:a == null ? b == null : a.equals(b)
。)
但是订单比较的处理方式不同。它使用 Comparable
接口:只有具有“自然排序”的类型才能实现;那些没有的,不能以这种方式进行比较。由于 null 不能实现任何接口,它不能有自然顺序,编译器会阻止你尝试比较。 (Kotlin 的 documentation doesn't make this explicit, because the parameter is non-nullable; but that for the underlying Java interface says 这样的比较应该 return 一个 NullPointerException。)
至于你应该如何处理这个问题,Elvis 运算符可能是最简洁的解决方案:
if (mouseEvent?.clickCount ?: 0 >= 2)
如果mouseEvent
不为空,这将得到它的clickCount
;否则,安全调用 ?.
将直接给出空值,然后 ?:
将替换为 0。(如果 clickCount
保持为空也会发生这种情况,尽管这不应该是可能。)在每种情况下,您最终都会得到一个可以安全地与 2 进行比较的不可为 null 的整数。
当然,在实践中,不应该调用侦听器方法并传递空事件。 (我不记得以前我曾经以编写 Java Swing 代码为生,也没有因此遇到过任何问题。)因此,一个更简单的替代方法可能是将参数声明为不可空的。但是正确处理 null 只是稍微安全一点;在这种情况下,它不会添加太多额外的代码。所以这取决于你!
多一点 kotlin 风格可以是这样的:
mouseEvent?.clickCount?.let{
if(it >= 2) {
launchSelectedSample()
}
}
更实用的风格:
mouseEvent?.clickCount?.takeIf { it >= 2 }?.let { launchSelectedSample() }
我是 Kotlin 新手。我正在学习一个教程,其中 GUI 部分涉及以下代码片段:
sampleList.addMouseListener(object: MouseAdapter() {
override fun mouseClicked(mouseEvent: MouseEvent?) {
if (mouseEvent?.clickCount == 2) {
launchSelectedSample()
}
}
})
mouseEvent
是 显然是 可空的 。在以前的编码经验中,我习惯于将 mouseEvent?.clickCount == 2
之类的行更改为 mouseEvent?.clickCount > 1
(或者可能是 >=2
), 以确保没有极端情况 其中点击发生得如此之快,以至于它从 1 跳到 3,或类似的东西。
所以,我将此代码切换为:
sampleList.addMouseListener(object: MouseAdapter() {
override fun mouseClicked(mouseEvent: MouseEvent?) {
if (mouseEvent?.clickCount >= 2) {
launchSelectedSample()
}
}
})
进行切换(将 ==2
更改为 >=2
)后,我从 IntelliJ 收到以下错误:
Operator call corresponds to a dot-qualified call 'mouseEvent?.clickCount.compareTo(2)' which is not allowed on a nullable receiver 'mouseEvent?.clickCount'.
这给我提出了 2 个问题:
- 为什么
==2
可以正常工作,而>=2
却不行? (我尝试了>1
,它给出了与>=2
相同的错误。) - 处理极端情况的正确方法是什么,我真正想要的是大于 1 的值?
我喜欢确保 null
s 在运行时不会搞砸的想法,但我有点希望 Kotlin 完全摆脱 null
值并做一些像 Rust 或 Haskell。 (不过,到目前为止,我确实喜欢我所看到的 Kotlin。)
当 mouseEvent == null
时,您期望 mouseEvent?.clickCount >= 2
有什么行为?
您可以使用 elvis (?:
) 运算符将 mouseEvent?.clickCount
转换为 NotNull:
val clickCount = mouseEvent?.clickCount ?: 0
if (clickCount >= 2) {
launchSelectedSample()
}
在这种情况下,如果 mouseEvent
为 null
mouseEvent?.clickCount
将为 0
==2
有效是因为 mouseEvent?.clickCount
被 Kotlin 视为 null
并且比较 null == 2
与 null >= 2
如您所见,Kotlin 的等式运算符(==
和 !=
)可以处理空值,而顺序比较运算符(<
、<=
、>
, >=
) 不能。
这可能是因为对于空值,意味着 什么相等性检查是显而易见的 — 两个空值显然相等,非空值永远不应该等于空值 — 而事实并非如此完全清楚它对订单比较意味着什么。 (如果 null 不 < 0,是否意味着 null >= 0?如果不是,则您不再有明确定义的顺序。)
这体现在实现上:Any
有一个equals()
方法,表示可以检查所有对象是否相等。 (Kotlin 的 documentation makes it explicit, as does that for the underlying Java method,非 null 对象绝不能等于 null。)Kotlin 对 ==
和 !=
运算符的实现明确检查空值。 (a == b
转换为您必须在 Java 中拼出的内容:a == null ? b == null : a.equals(b)
。)
但是订单比较的处理方式不同。它使用 Comparable
接口:只有具有“自然排序”的类型才能实现;那些没有的,不能以这种方式进行比较。由于 null 不能实现任何接口,它不能有自然顺序,编译器会阻止你尝试比较。 (Kotlin 的 documentation doesn't make this explicit, because the parameter is non-nullable; but that for the underlying Java interface says 这样的比较应该 return 一个 NullPointerException。)
至于你应该如何处理这个问题,Elvis 运算符可能是最简洁的解决方案:
if (mouseEvent?.clickCount ?: 0 >= 2)
如果mouseEvent
不为空,这将得到它的clickCount
;否则,安全调用 ?.
将直接给出空值,然后 ?:
将替换为 0。(如果 clickCount
保持为空也会发生这种情况,尽管这不应该是可能。)在每种情况下,您最终都会得到一个可以安全地与 2 进行比较的不可为 null 的整数。
当然,在实践中,不应该调用侦听器方法并传递空事件。 (我不记得以前我曾经以编写 Java Swing 代码为生,也没有因此遇到过任何问题。)因此,一个更简单的替代方法可能是将参数声明为不可空的。但是正确处理 null 只是稍微安全一点;在这种情况下,它不会添加太多额外的代码。所以这取决于你!
多一点 kotlin 风格可以是这样的:
mouseEvent?.clickCount?.let{
if(it >= 2) {
launchSelectedSample()
}
}
更实用的风格:
mouseEvent?.clickCount?.takeIf { it >= 2 }?.let { launchSelectedSample() }