了解 Kotlin 类型系统,`{Comparable<{ Double & Int }> & Number}` 是什么意思以及如何使用它

Understanding Kotlin Type system, What is meant by `{Comparable<{ Double & Int }> & Number}` and how to work with that

例如:

var a = true
val test = if (a) -1 else -3.2

我期待 test 的类型应该是类型层次结构的最接近的交集,即 Int 和 Double 是 Number

但是看IDE,好像是{Comparable<{ Double & Int }> & Number}的类型。

奇怪的是,我不能那样指定它(因为 {} 是为创建 lambda 保留的),我只能将它设置为 Number.

类型

另一个奇怪的事情是,如果我从 Comparable 接口尝试一些函数,它会抛出一些错误:

// Warning at value 2
// The integer literal does not conform to the expected type {Double & Int}
test.compareTo(2)

3.compareTo(-1.1) // possible
2.3.compareTo(100) // possible

// But why not this is possible, while it has inferred type of Comparable?
test.compareTo(2)

有人可以帮助理解这里的概念吗?还有几个问题:

问题 1 的答案是编译器正在尽最大努力推断类型,发明新的约束来描述它。

问题 2 的答案是不能。

问题 3 的答案是不能,因为 IntDouble 不可比,反之亦然。因此 Comparable 中的 none 方法实际上是可用的,但该值肯定实现了 Comparable 反对 某事 。这对 Comparable 没有用,但可能对另一个接口有用。例如,假设:

interface ZeroAndComparable<T> {
  fun compareTo(t: T): Int
  fun zero(): T
}

val foo : ZeroAndComparable<Int> = someZeroAndComparableInt()
val bar : ZeroAndComparable<Double> = someZeroAndComparableDouble()
val foobar = if (a) foo else bar
val zero : Any = foobar.zero() // should work
foobar.compareTo(something) // cannot work

& 这里表示交集类型(Kotlin 语言本身不支持,但编译器在内部使用它们)。你可以看到它在(不完整)specification.

中提到

Intersection types are special non-denotable types used to express the fact that a value belongs to all of several types at the same time.

"Non-denotable" 恰恰意味着您不能指定该类型。我不确定,但我认为类型中额外的 { } 应该准确地表明这一点。

特别是,Comparable<Double & Int> 意味着您只能将 test DoubleInt 进行比较,但是没有这样的值。编译器可能会将其简化为 Comparable<Nothing>.

the most closest intersection of the type-hierarchy i.e. for Int and Double is Number.

  1. 是最小上界,更接近于并集,而不是交集。规范实际上称它为 "union types",但这不是该术语的正常用法。

  2. 这个最小上限不是 Number 因为它 Comparable 接口的最小上限Comparable<Double & Int> 因为 Comparable 是逆变的:

    lub(Int, Double) = 
    Number & lub(Comparable<Int>, Comparable<Double>) =
    Number & Comparable<Int & Double>
    

此计算在 type decaying 下进行了描述:

All union types are subject to type decaying, when they are converted to a specific intersection type, representable within Kotlin type system.