Kotlin 泛型类型参数

Kotlin Generics type parameters

在下面的源代码

fun main(args: Array<String>) {
    println("Hello, world!")

    val mutableIntList = mutableListOf(1, 2, 3)

    addInt(4, mutableIntList) // No compile-time error
    addAnotherInt(5, mutableIntList) // Compile-time error

    println(mutableIntList)

}

fun <T: Number> addInt(item:T,
                       list:MutableList<in T>){
    list.add(item)
}

fun <T: Number> addAnotherInt(item:T,
                              list:MutableList<in Number>){
    list.add(item)
}

函数addIntaddAnotherIntNumber的逆变MutableList作为参数。但是在 main 函数中,一行可以正常编译,而另一行则不能。

我还检查了这些函数生成的 java 代码,它们看起来完全相同。

函数 addIntaddAnotherInt 之间可能有什么区别?

in Number 表示“Number 或其超类型”。 Int 不是“Number 或其超类型”,而是其子类型。

简而言之,您声明您的 addAnotherInt() 想要一个至少与接受任何类型的 Number.

一样通用的列表

相比之下,addInt 声明了 item: Tlist: MutableList<in T>T 本身被声明为函数的 自由类型变量 ,这意味着它将绑定在每个特定的调用站点。所以当你说

addInt(4, mutableIntList)

Kotlin 根据第一个参数将 T 绑定到 Int,并将其传播到第二个参数,现在是 MutableList<in Int>。您传入了与该类型兼容的 MutableList<Int>,因此 Kotlin 已满足。

如果你声明

val mutableIntList: MutableList<Number> = mutableListOf(1, 2, 3)

然后代码将编译,因为现在列表已按要求通用,您可以向其中添加任何 Number

您的代码将使用数字列表进行编译:

val mutableIntList = mutableListOf<Number>(1, 2, 3)

但是由于类型被推断为 MutableList<Int>,您不能将其用作 MutableList<in Number>。这转换为 Java 等价物 MutableList<? super Number> 并且意味着您可以将任何 Number 添加到列表中。但是向 MutableList<Int> 添加 Long 是不可能的。

您的第二种方法 addInt() 稍微严格一些,并在您的用例中翻译 MutableList<? super Int>。因此你可以这样使用它。不过,这两种方法都可以使用 MutableList<Number>