美文网首页
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 Weekly 中文周报 —— 23

    Kotlin 开发中文周报 文章 Kotlin 泛型『in』和『out』的变体(android.jlelse.eu...

  • Kotlin-泛型

    源自:码上开学-Kotlin的泛型 kotlin的in和out对应的是java中带上界和下界的通配符?号。【in】...

  • Kotlin(1.1)学习笔记(6)——泛型

    in和out 和java一样,kotlin中也有泛型的概念。不同的是,java中使用了通配符而kotlin中不存在...

  • Kotlin 泛型中的 in 和 out

    简评:在 Kotlin 中使用泛型你会注意到其中引入了 in 和 out,对于不熟悉的开发者来说可能有点难以理解。...

  • Kotlin 泛型中的 in 和 out

    协变 在 Java 的泛型系统中. 泛型默认是不支持协变(covariant). 也就是说在 Java 中. 即使...

  • Kotlin泛型中的In和Out

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

  • Java泛型通配符,上下界。

    为了理清楚泛型的通配符和上下界的作用,并为了Kotlin的泛型中的关键字in和out的理解,在此用小demo重新梳...

  • 网址笔记记录

    1.Kotlin 泛型中的 in 和 out https://www.jianshu.com/p/c5ef8b30...

  • kotlin 泛型 :out in

    * in。它使得一个类型参数逆变:只可以被写入而不可以被读取(相当于Java中 ? super T) * out ...

  • Kotlin开发知识(一)

    1.Kotlin泛型使用 Out(协变) 如果你的类是将泛型作为内部方法的返回,那么可以用out。可以称其为pro...

网友评论

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

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