Kotlin:相等比较在可以为null的情况下似乎可以,但是大于比较则不能

时间:2019-03-28 16:34:34

标签: kotlin nullable

我是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'.

这对我提出了两个问题:

  1. 为什么==2可以正常工作,但是>=2却不能正常工作? (我尝试过>1,该错误与>=2相同。)
  2. 处理拐角情况的正确方法是什么,我真正想要的是大于1的情况?

我喜欢确保null在运行时不会出错的想法,但是我有点希望Kotlin是否完全摆脱了null值,并做了Rust或Haskell之类的事情。 (不过,我确实很喜欢到目前为止对Kotlin的了解。)

3 个答案:

答案 0 :(得分:3)

如您所见,Kotlin的相等运算符(==!=)可以处理空值,而顺序比较运算符(<<=,{{1 }},>)。

这可能是因为很明显,什么相等检查应该均值检查空值-两个空值显然相等,并且一个非空值永远不应该等于空值-尽管根本不清楚应该意味着订单比较。 (如果null不小于0,是否意味着null> = 0?否则,您将不再有明确定义的顺序。)

这反映在实现中:>=有一个Any方法,指示可以检查所有对象是否相等。 (Kotlin的documentation并未明确指出,但对于基础Java方法says而言,非null对象绝不能等于null。)还有Kotlin对equals()和{{ 1}}运算符显式检查是否为空。 ({==转换为您必须用Java拼写的内容:!=。)

但是订单比较的处理方式有所不同。它使用a == b接口:只有具有“自然顺序”的类型才能实现;那些没有的,就无法以这种方式进行比较。由于null无法实现任何接口,因此它不能具有自然顺序,并且编译器会阻止您尝试比较。 (同样,Kotlin的documentation对此并不明确,因为该参数不可为空;但是底层Java接口says的文档中,这样的比较应返回NullPointerException。)

关于如何处理此问题,猫王运算符可能是最简洁的解决方案:

a == null ? b == null : a.equals(b)

如果Comparable不为null,它将得到其if (mouseEvent?.clickCount ?: 0 >= 2) ;否则,安全呼叫mouseEvent将直接给出null,然后clickCount将替换为0。(如果?.保持为null,也不会发生这种情况,但这不应该是在每种情况下,您最终都会得到一个非空整数,可以安全地与2进行比较。

当然,在实践中,绝对不应调用侦听器方法并传递null事件。 (我不记得曾经写过Java Swing代码来谋生,或者遇到任何问题。)所以一个更简单的选择可能是将参数声明为不可为空。但是正确处理null只是稍微安全一点。在这种情况下,它不会添加太多额外的代码。因此,取决于您!

答案 1 :(得分:1)

date enseamble 2009-08-02 0 2009-08-03 0 2009-08-04 0 2009-08-05 0 2009-08-06 -1 2009-08-07 1 发生时,您期望mouseEvent?.clickCount >= 2发生什么行为?

您可以使用elvis(mouseEvent == null)运算符将mouseEvent?.clickCount转换为NotNull:

?:

在这种情况下,如果val clickCount = mouseEvent?.clickCount ?: 0 if (clickCount >= 2) { launchSelectedSample() } 为空,则mouseEvent?.clickCount将为0

mouseEvent之所以有效,是因为==2被科特林(Kotlin)认为是mouseEvent?.clickCount,而比较null是正确的,与null == 2不同

答案 2 :(得分:1)

更多的科特林风格可以是:

mouseEvent?.clickCount?.let{ 
  if(it >= 2) {
    launchSelectedSample()
  }
}

更加实用的风格:

mouseEvent?.clickCount?.takeIf { it >= 2 }?.let { launchSelectedSample() }