正文
简评:在 Kotlin 中使用泛型你会注意到其中引入了 in 和 out,对于不熟悉的开发者来说可能有点难以理解。从形式上讲,这是一种定义
逆变和协变
的方式,这篇文章就来讲讲怎么来理解和记住它们。
in & out 怎么记?
Out (协变)
如果你的类是将泛型作为内部方法的返回,那么可以用 out:
interface Production<out T> {
fun produce(): T
}
可以称其为 production class/interface,因为其主要是产生(produce)指定泛型对象。因此,可以这样来记:
produce = output = out
。
In(逆变)
如果你的类是将泛型对象作为函数的参数,那么可以用 in:
interface Consumer<in T> {
fun consume(item: T)
}
可以称其为 consumer class/interface,因为其主要是消费指定泛型对象。因此,可以这样来记:
consume = input = in。
Invariant(不变)
如果既将泛型作为函数参数,又将泛型作为函数的输出,那就既不用 in 或 out。
interface ProductionConsumer<T> {
fun produce(): T
fun consume(item: T)
}
举个例子
假设我们有一个汉堡(burger)对象,它是一种快餐,当然更是一种食物。
open class Food
open class FastFood : Food()
class Burger : FastFood()
1. 汉堡提供者
根据上面定义的类和接口来设计提供
food, fastfood
和
burger
的类:
class FoodStore : Production<Food> {
override fun produce(): Food {
println("Produce food")
return Food()
}
}
class FastFoodStore : Production<FastFood> {
override fun produce(): FastFood {
println("Produce food")
return FastFood()
}
}
class InOutBurger : Production<Burger> {
override fun produce(): Burger {
println("Produce burger")
return Burger()
}
}
现在,我们可以这样赋值:
val production1 : Production<Food> = FoodStore()
val production2 : Production<Food> = FastFoodStore()
val production3 : Production<Food> = InOutBurger()
很显然,汉堡商店属于是快餐商店,当然也属于食品商店。
因此,对于 out 泛型,我们能够将使用子类泛型的对象赋值给使用父类泛型的对象。
而如果像下面这样反过来使用子类 - Burger 泛型,就会出现错误,因为快餐(fastfood)和食品(food)商店不仅仅提供汉堡(burger)。
val production1 : Production<Burger> = FoodStore() // Error
val production2 : Production<Burger> = FastFoodStore() // Error
val production3 : Production<Burger> = InOutBurger()
2. 汉堡消费者
再让我们根据上面的类和接口来定义汉堡消费者类:
class Everybody : Consumer<Food> {
override fun consume(item: Food) {
println("Eat food")
}
}
class ModernPeople : Consumer<FastFood> {
override fun consume(item: FastFood) {
println("Eat fast food")
}
}
class American : Consumer<Burger> {
override fun consume(item: Burger) {
println("Eat burger")
}
}
现在,我们能够将
Everybody, ModernPeople
和 American 都指定给汉堡消费者(Consumer<Burger>):
val consumer1 : Consumer<Burger> = Everybody()
val consumer2 : Consumer<Burger> = ModernPeople()
val consumer3 : Consumer<Burger> = American()
很显然这里美国的汉堡的消费者既是现代人,更是人类。