* 基本上意味着你不知道在这种情况下T 是什么类型,所以它可以是任何东西。
因为您已将d 定义为Data<*>,所以调用d.get() 返回Any?。编译器无法知道d 包含什么类型的数据。因此你必须期待任何对T 有效的东西,包括null。
因为您已将d 定义为Data<*>,所以调用d.update(…) 只接受Nothing,即没有任何价值。编译器无法知道d 允许接收什么类型的数据。因此它不能接受任何东西,因为它在这里可能有效也可能无效。
您想告诉编译器的是,d 的输出(投影外)和 d 的输入(投影)之间存在关系:
fun <T> alterData(d: Data<T>) {
d.update(d.get())
}
现在编译器知道d(通过.get())产生的任何内容与您放入d(通过.update(…))的类型相同。在这两种情况下,该类型都称为T。
请注意,“类型参数”T 不必与您的 Data<T> 声明具有相同的名称。以下同样有效地表明了这种关系:
fun <Something> alterData(d: Data<Something>) {
d.update(d.get())
}
如果你进一步分解代码可能更容易理解:
fun alterData(d: Data<*>) {
// `value` is of type `Any?` because we don't know `T` of `Data`
val value = d.get()
// `update` rejects `Any?` b/c we don't know `T` and it may not be valid
d.update(value)
}
fun <Something> alterData(d: Data<Something>) {
// `value` is of type `Something` b/c we know that `T` of `Data` is `Something`
val value = d.get()
// `update` accepts `Something` b/c we know `T` is `Something`
d.update(value)
}
在你的情况下,调用者和被调用者 (alterData) 都不知道 T 的实际类型,你必须告诉编译器使用强制转换忽略编译时类型安全。
您可以在调用者或被调用者中执行此操作。更有意义的地方取决于实际用例。通常调用者比被调用者更了解上下文和T 的可能类型,因此在那里执行强制转换是有意义的。
fun foo(d: Data<*>) {
// ignore all type safety for `T`
alterData(d as Data<Any?>)
}
被调用者 alterData 立即将它从一个 Data 实例 (d) 接收到的值传递回同一实例。在这种情况下,鉴于您对class Data 的定义,可以安全地假设这永远不会出错。如果是这种情况,那么您可以在 alterData 函数中安全地执行该案例:
fun alterData(d: Data<*>){
// ignore type safety and allow any value to be passed into `d`
(d as Data<Any?>).update(d.get())
}
这两种方法都会引发编译器警告,您可以使用 @Suppress("UNCHECKED_CAST") 忽略该警告。