in and out in Kotlin Generics

Short comment: When using generics in Kotlin you will notice the introduction of in and out, which may be a bit confusing for unfamiliar developers. Formally, this is a way of defining contravariance and covariance , and this article will explain how to understand and remember them.

How to remember in & out?

Out (covariant)

If your class returns generics as internal methods, you can use out:

interface Production<out T> {

    fun produce(): T
}

It can be called a production class/interface because it mainly produces the specified generic object. Therefore, it can be written like this: produce = output = out .

In (inverted)

If your class takes generic objects as function parameters, you can use in:

interface Consumer<in T> {

    fun consume(item: T)

}

It can be called consumer class/interface because it mainly consumes specified generic objects. Therefore, it can be written like this: consume = input = in.

Invariant (unchanged)

If you have generics as function parameters and generics as the output of the function, then neither in nor out is used.

interface ProductionConsumer<T> {

    fun produce(): T
   fun consume(item: T)

}

for example

Suppose we have a burger object, which is a fast food and of course a food.

0?wx_fmt=jpeg

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

1. Burger Provider

Design the classes that provide food, fastfood  and  burger according to the classes and interfaces defined above   :

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

Now, we can assign values ​​like this:

val production1 : Production<Food> = FoodStore()
val production2 : Production<Food> = FastFoodStore()
val production3 : Production<Food> = InOutBurger()

Obviously, a burger store is a fast food store, and of course a food store.

So, with out generics, we can assign objects that use subclass generics to objects that use superclass generics.

And if you use the subclass - Burger generic in reverse like below, you will get an error because fastfood and food stores don't just serve burgers.

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

2. Burger consumers

Let's define the hamburger consumer class based on the above class and interface:

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()

很显然这里美国的汉堡的消费者既是现代人,更是人类。

Therefore, for in generics, we can assign an object that uses the superclass generic to an object that uses the subclass generic.

Similarly, if the parent class - Food generic is used in reverse here, an error will be reported:

val consumer1 : Consumer<Food> = Everybody()
val consumer2 : Consumer<Food> = ModernPeople()  // Error
val consumer3 : Consumer<Food> = American()  // Error

Based on the above, we can also understand when to use in and out in this way:

  • The parent class generic object can be assigned to the subclass generic object, use in;

  • Subclass generic objects can be assigned to superclass generic objects with out.

0?wx_fmt=jpeg

English original : In and out type variant of Kotlin

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325581324&siteId=291194637