美文网首页
Kotlin泛型中的In和Out

Kotlin泛型中的In和Out

作者: 竖起大拇指 | 来源:发表于2021-06-18 11:08 被阅读0次

    当我们在Kotlin中定义泛型时,我们会发现它需要使用inout两个关键字来定义。从形式上来讲,
    这是一种定义逆变协变的方式。

    1.in & out 怎么记?

    1.1 out (协变)

    如果泛型类只将泛型类型作为函数的返回(输出),那么使用out:

    interface Production<out T> {
        fun produce(): T
    }
    

    可以称之为生产类/接口,因为它主要是用来生产指定的泛型对象。因此,我们可以简单地这样记忆:

    produce=output=out

    1.2 in(逆变)

    如果泛型类只将泛型类型作为函数的入参(输入),那么使用in:

    interface Consumer<in T> {
        fun consume(item: T)
    }
    

    可以称之为消费者类/接口,因为它主要是用来消费(consume)指定的泛型对象。因此我们可以简单地这样记忆:

    consume=input=in

    1.3 invariant(不变)

    如果泛型类既将泛型类型作为函数参数,又将泛型类型作为函数输入,那么既不用out也不用in:

    interface ProductionConsumer<T> {
        fun produce(): T
        fun consume(item: T)
    }
    

    2. 为啥要使用 in & out ?

    举个例子,我们定义下汉堡类对象,它是一种快餐,也是一种食物。

    open class Food
    open class FastFood : Food()
    class Burger : FastFood()
    

    2.1 汉堡生产者

    根据上面定义的生产(Production)接口,我们可以进一步扩展它们来生产食物,快餐和汉堡:

    class FoodStore : Production<Food> {
        override fun produce(): Food {
            println("Produce food")
            return Food()
        }
    }
    
    class FastFoodStore : Production<FastFood> {
        override fun produce(): FastFood {
            println("Produce fast 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类型,我们能够将使用子类泛型的对象赋值给使用父类泛型的对象。[协变]

    如果我们修改如下,那么就会报错,因为食物或快餐店可以生产汉堡,但不一定仅仅生产汉堡:

    val production1 : Production<Burger> = FoodStore()  // Error
    val production2 : Production<Burger> = FastFoodStore()  // Error
    val production3 : Production<Burger> = InOutBurger()
    

    2.2 汉堡消费者

    根据上面定义的消费(Consumer)接口,我们可以进一步扩展它们来消费食物,快餐和汉堡:

    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")
        }
    }
    

    我们可以将人类,现代人,美国人指定为汉堡消费者,所以可以这样赋值:

    val consumer1 : Consumer<Burger> = Everybody()
    val consumer2 : Consumer<Burger> = ModernPeople()
    val consumer3 : Consumer<Burger> = American()
    

    因此,对于 in 泛型,我们能够将使用父类泛型的对象赋值给使用子类泛型的对象。 [ 逆变]

    3.记住 in & out 的另一种方式

    • 父类泛型对象可以赋值给子类泛型对象,用 in;
    • 子类泛型对象可以赋值给父类泛型对象,用 out。

    相关文章

      网友评论

          本文标题:Kotlin泛型中的In和Out

          本文链接:https://www.haomeiwen.com/subject/rhrkyltx.html