Eit*_*s30 3 generics covariance contravariance kotlin
我正在寻找一个在类声明中使用out时可能导致问题的示例,并且该类有一个将参数类型作为参数的方法。
另外,我正在寻找一个在类声明中使用in且参数类型是类的var成员时可能导致问题的示例?我认为我只能通过例子来理解规则
假设这些是我们正在使用的类:
open class Animal
class Cat: Animal() {
fun meow() = println("meow")
}
Run Code Online (Sandbox Code Playgroud)
如果我们创建一个像这样具有协变out类型的类,并且编译器允许我们使用该类型作为函数参数:
class Foo<out T: Animal> {
private var animal: T? = null
fun consumeValue(x: T) { // NOT ALLOWED
animal = x
}
fun produceValue(): T? {
return animal
}
}
Run Code Online (Sandbox Code Playgroud)
那么如果你这样做,将会导致一种不可能的情况,我们试图调用meow一个没有meow函数的 Animal:
val catConsumer = Foo<Cat>()
val animalConsumer: Foo<Animal> = catConsumer // upcasting is valid for covariant type
animalConsumer.consumeValue(Animal())
catConsumer.produceValue()?.meow() // can't call `meow` on plain Animal
Run Code Online (Sandbox Code Playgroud)
如果我们创建一个这样的具有逆变in类型的类,并且编译器允许我们使用该类型作为返回值:
class Bar<in T: Animal>(private val library: List<T>) {
fun produceValue(): T { // NOT ALLOWED
return library.random()
}
}
Run Code Online (Sandbox Code Playgroud)
那么如果这样做,将导致编译器无法将返回类型转换为子类型。
val animalProducer: Bar<Animal> = Bar(List(5) { Animal() })
val catProducer: Bar<Cat> = animalProducer // downcasting is valid for contravariant type
catProducer.produceValue().meow() // can't call `meow` on plain Animal
Run Code Online (Sandbox Code Playgroud)
属性有一个 getter,就像一个返回值的函数,var属性还有一个 setter,就像一个带有参数的函数。因此,属性与逆变 ( )val不兼容,并且属性与逆变或协方差 ( ) 不兼容。私有属性不受这些限制的影响,因为在类的内部工作中,类型是不变的。类所能知道的关于它自己类型的所有信息就是它的边界。差异只会影响外部世界如何投射(查看)该类。invarout
因此,一个例子val就足以说明为什么任何属性都与逆变不相容。你可以val用var下面的替换,它不会有什么不同。
class Bar<in T: Animal>(
val animal: T // NOT ALLOWED
)
val animalProducer: Bar<Animal> = Bar(Animal())
val catProducer: Bar<Cat> = animalProducer // downcasting is valid for contravariant type
catProducer.animal.meow() // can't call `meow` on plain Animal
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
495 次 |
| 最近记录: |