当涉及到协变和逆变时,Kotlin 的 out 和 in 关键字可以提供更精确的类型约束。下面是一些在 Kotlin 中使用 out 和 in 的示例:
1.协变(out)示例:
open class Animal(val name: String)
class Cat(name: String) : Animal(name)
class Dog(name: String) : Animal(name)
interface AnimalProducer<out T> {
fun produce(): T
}
fun main() {
val catProducer: AnimalProducer<Cat> = object : AnimalProducer<Cat> {
override fun produce(): Cat {
return Cat("Whiskers")
}
}
val animalProducer: AnimalProducer<Animal> = catProducer // 协变,Cat 是 Animal 的子类型
val animal: Animal = animalProducer.produce() // 可以生产 Animal
println(animal.name) // 输出 "Whiskers"
val cat: Cat = catProducer.produce() // 可以生产 Cat
println(cat.name) // 输出 "Whiskers"
}
在上述示例中,AnimalProducer<out T> 接口使用了 out 关键字来声明 T 为协变类型参数。这意味着 AnimalProducer<Cat> 是 AnimalProducer<Animal> 的子类型,因为 Cat 是 Animal 的子类型。
2.逆变(in)示例:
open class Animal(val name: String)
class Cat(name: String) : Animal(name)
class Dog(name: String) : Animal(name)
interface AnimalConsumer<in T> {
fun consume(animal: T)
}
fun main() {
val animalConsumer: AnimalConsumer<Animal> = object : AnimalConsumer<Animal> {
override fun consume(animal: Animal) {
println("Consuming animal: ${animal.name}")
}
}
val catConsumer: AnimalConsumer<Cat> = animalConsumer
animalConsumer.consume(Animal("Animal")) // 可以消费 Animal
animalConsumer.consume(Cat("Whiskers")) // 可以消费 Cat
catConsumer.consume(Animal("Animal")) // 会报错 仅可以消费 Cat
catConsumer.consume(Cat("Whiskers")) // 仅可以消费 Cat
}
在上述示例中,AnimalConsumer<in T> 接口使用了 in 关键字来声明 T 为逆变类型参数。这意味着 AnimalConsumer<Cat> 是 AnimalConsumer<Animal> 的子类型,因为 AnimalConsumer<Animal> 可以接受 Animal 或其子类型作为输入。我们可以使用 animalConsumer 对象消费 Cat 对象或 Animal 对象,但 catConsumer 对象只能消费 Cat 对象。
以上示例演示了在 Kotlin 中使用 out 和 in 关键字来实现泛型的协变和逆变,从而提供更精确的类型约束。
网友评论