让我们考虑以下简化示例:
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是否相同,但是我想在运行程序之前先了解一下。我该怎么办?
答案 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 ""
不应该编译,对吗?错误!编译器“有帮助地”推断出A
为Any
,这在Haskell中是无法做到的。
另一个问题:您可以比较类型Interface1
和Interface2
的值吗?它们之所以相等,是因为它们都可以属于实现两个接口的类。
您可以实际上在Scala中做到这一点,因为类型推断在此处的工作方式有所不同,但是我认为对于Kotlin而言,没有一个好的解决方案。