Kotlin Generics类型参数

时间:2018-02-02 10:18:52

标签: generics kotlin contravariance

以下源代码

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)
}

函数addIntaddAnotherIntMutableList的逆变Number作为参数。但是在main函数中,一行正常编译而另一行不正常编译。

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

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

2 个答案:

答案 0 :(得分:8)

in Number表示&#34; Number或其超类型&#34;。 Int不是&#34; Number或其超类型&#34;,它是它的子类型。

简单来说,您声明您的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

答案 1 :(得分:2)

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

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

但由于该类型推断为MutableList<Int>,因此您无法将其用作MutableList<in Number>。这转换为 Java 等效MutableList<? super Number>,意味着您可以向列表添加任何Number。但是无法向Long添加MutableList<Int>

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