Kotlin 泛型中的 in 和 out,kotlinout

來源:互聯網
上載者:User

Kotlin 泛型中的 in 和 out,kotlinout

價值 | 思考 | 共鳴


簡評:在 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 Foodopen 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()

很顯然這裡美國的漢堡的消費者既是現代人,更是人類。

因此,對於 in 泛型,我們可以將使用父類泛型的對象賦值給使用子類泛型的對象。

同樣,如果這裡反過來使用父類 - Food 泛型,就會報錯:

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

根據以上的內容,我們還可以這樣來理解什麼時候用 in 和 out:

  • 父類泛型對象可以賦值給子類泛型對象,用 in;

  • 子類泛型對象可以賦值給父類泛型對象,用 out。

英文原文:In and out type variant of Kotlin

舊文推薦:用 Kotlin 開發現代 Android 項目 Part 1

▼點擊閱讀原文擷取文中連結

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。 http://blog.csdn.net/IaC743nj0b/article/details/79017052

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.