Kotlin:防止==类型错误的编译

时间:2018-06-24 21:17:47

标签: kotlin

让我们考虑以下简化示例:

interface I { /* some stuff */ }

object A: I { /* some stuff */ }

object B: I { /* some more stuff */ }

class Cell<J: I>(val n: Int, val j: J) {
   /* some more stuff that uses j */
   fun eq(c: Cell<J>): Boolean {
       return n == c.n
   }
}

现在Cell(1, A).eq(Cell(2, A))可以编译,但是Cell(1, A).eq(Cell(2, B))不能正常编译。

现在,我想将eq替换为==。可悲的是,我看到的唯一方法是:

class Cell<J: I>(val i: Int, val j: J) {
   override fun equals(c: Any?): Boolean {
       c as Cell<J>
       return i == c.i
   }
}

这样做的缺点是Cell(1, A) == Cell(2, B)会愉快地编译。我当然可以在运行时检查j是否相同,但是我想在运行程序之前先了解一下。我该怎么办?

2 个答案:

答案 0 :(得分:3)

您当前拥有的就是解决方案。 equals没有任何类型安全性。

使用类型安全性,除非您先指定更高层的类型,否则您将无法正确比较不同抽象上的类型:

class Sub : Super
class Super(val num: Int)

fun compare(sub: Sub, super: Super) {
    val superFirst = super == sub // would compile
    val subFirst = sub == super // wouldn't compile
}

因此equals指定严格的参数没有意义。

equals函数的参数为​​Any,因此您将永远不会从中获得类型安全。您也不能重载运算符,因为这样做会引发错误。

equals的唯一目的是在运行时检查是否相等(通过潜在的类型检查和状态检查),因此它不是解决此问题的合适工具。

答案 1 :(得分:1)

  

我一直在寻找类似于==在Haskell中工作的方式。

即使您不需要将其命名为==,也无法与JVM子类型互操作,而Kotlin需要支持JVM子类型(而Haskell当然不需要)。查看失败的尝试可能是有益的:

public infix fun <A> A.eq(x: A) = this == x

这要求接收者和参数具有相同的类型A,因此1 eq ""不应该编译,对吗?错误!编译器“有帮助地”推断出AAny,这在Haskell中是无法做到的。

另一个问题:您可以比较类型Interface1Interface2的值吗?它们之所以相等,是因为它们都可以属于实现两个接口的类。

可以实际上在Scala中做到这一点,因为类型推断在此处的工作方式有所不同,但是我认为对于Kotlin而言,没有一个好的解决方案。