Kotlin 中的逆变
Contravariance in Kotlin
我从来没有真正理解 Java 中的泛型,所以 Kotlin 似乎也是如此。考虑以下代码片段(这是一个人为的示例):
class AnyComparator: Comparator<Any> {
override fun compare(o1: Any, o2: Any): Int {
TODO("not implemented")
}
}
fun <T> test() {
val x: Comparator<in Double> = AnyComparator() // OK!
val y: Comparator<in T> = AnyComparator() // Compilation error
}
第二次赋值失败,错误为
Type mismatch.
Required: kotlin.Comparator<in T>
Found: AnyComparator
现在,如果我理解正确,in
修饰符表示 T
仅由泛型类型 Comparator
使用(它使逆变),所以我应该能够分配任何 Comparator
类型参数 E
是 T
的基础 class。基于此,我应该能够将 AnyComparator
分配给变量 x
和 y
,因为类型 Any
是每个 [=] 的基础 class 29=] 在科特林中。原来我做不到,我也不明白为什么。
这看起来很奇怪,但 Any
不是所有 kotlin 类 的超类,而只是不可空 类 的超类。所有 Kotlin 类 的真正超类是 Any?
(它也是 Any
的超类)。
您的 test
函数中的通用类型 T
没有上限,因此它可以是可为 null 的对象 Any?
。错误是因为当你需要 Comparator<Any?>
.
时你不能 Comparator<Any>
因此,您可以修复将 T
上限定义为 Any
:
的示例
fun <T: Any> test() {
//...
}
只是想补充 Fabio 的答案,有吗?不是 kotlin 中所有 类 的超类,但 Any 是 Any 的子类型?在技术上是正确的。例如:
val string1: String = "Sarabjit"
// val newString2 : String = null [this does not work as we cannot assign null to a String which cannot hold a null value
var checkString: String? = newString1
checkString = null //This works like a charm.
我从来没有真正理解 Java 中的泛型,所以 Kotlin 似乎也是如此。考虑以下代码片段(这是一个人为的示例):
class AnyComparator: Comparator<Any> {
override fun compare(o1: Any, o2: Any): Int {
TODO("not implemented")
}
}
fun <T> test() {
val x: Comparator<in Double> = AnyComparator() // OK!
val y: Comparator<in T> = AnyComparator() // Compilation error
}
第二次赋值失败,错误为
Type mismatch.
Required: kotlin.Comparator<in T>
Found: AnyComparator
现在,如果我理解正确,in
修饰符表示 T
仅由泛型类型 Comparator
使用(它使逆变),所以我应该能够分配任何 Comparator
类型参数 E
是 T
的基础 class。基于此,我应该能够将 AnyComparator
分配给变量 x
和 y
,因为类型 Any
是每个 [=] 的基础 class 29=] 在科特林中。原来我做不到,我也不明白为什么。
这看起来很奇怪,但 Any
不是所有 kotlin 类 的超类,而只是不可空 类 的超类。所有 Kotlin 类 的真正超类是 Any?
(它也是 Any
的超类)。
您的 test
函数中的通用类型 T
没有上限,因此它可以是可为 null 的对象 Any?
。错误是因为当你需要 Comparator<Any?>
.
Comparator<Any>
因此,您可以修复将 T
上限定义为 Any
:
fun <T: Any> test() {
//...
}
只是想补充 Fabio 的答案,有吗?不是 kotlin 中所有 类 的超类,但 Any 是 Any 的子类型?在技术上是正确的。例如:
val string1: String = "Sarabjit"
// val newString2 : String = null [this does not work as we cannot assign null to a String which cannot hold a null value
var checkString: String? = newString1
checkString = null //This works like a charm.