Kotlin 泛型中的 in 和 out

2021-09-13 21:07:59 字數 2422 閱讀 1281

當我們在 kotlin 中定義泛型時,我們會發現它需要使用到inout兩個關鍵字來定義。從形式上來講,這是一種定義「逆變」和「協變」的方式。

那啥叫逆變?啥叫協變?可以參考下維基百科的定義:協變與逆變

out(協變)

如果泛型類只將泛型型別作為函式的返回(輸出),那麼使用 out:

inte***ce production
可以稱之為生產類/介面,因為它主要是用來生產(produce)指定的泛型物件。因此,我們可以簡單地這樣記憶:

produce = output = out

in(逆變)

如果泛型類只將泛型型別作為函式的入參(輸入),那麼使用 in:

inte***ce consumer
可以稱之為消費者類/介面,因為它主要是用來消費(consume)指定的泛型物件。因此我們可以簡單地這樣記憶:

consume = input = in

invariant(不變)

如果泛型類既將泛型型別作為函式引數,又將泛型型別作為函式的輸出,那麼既不用 out 也不用 in:

inte***ce productionconsumer
舉個例子,我們定義下漢堡類物件,它是一種快餐,也是一種食物。

open class food

open class fastfood : food()

class burger : fastfood()

漢堡生產者

根據上面定義的生產(production)介面,我們可以進一步擴充套件它們來生產食物、快餐和漢堡:

class foodstore : production

}class fastfoodstore : production

}class inoutburger : production

}

現在,我們可以這樣賦值:

val production1 : production= foodstore()

val production2 : production= fastfoodstore()

val production3 : production= inoutburger()

顯然,漢堡商店屬於快餐商店,也屬於食物商店。

因此,對於 out 型別,我們能夠將使用子類泛型的物件賦值給使用父類泛型的物件。

如果我們修改如下,那麼就會出錯了,因為食物或快餐商店是可以生產漢堡,但不一定僅僅生產漢堡:

val production1 : production= foodstore()  // error

val production2 : production= fastfoodstore() // error

val production3 : production= inoutburger()

漢堡消費者

根據上面定義的消費(consumer)介面,我們可以進一步擴充套件它們來消費食物、快餐和漢堡:

class everybody : consumer

}class modernpeople : consumer

}class american : consumer

}

我們可以將人類、現代人、美國人指定為漢堡消費者,所以可以這樣賦值:

val consumer1 : consumer= everybody()

val consumer2 : consumer= modernpeople()

val consumer3 : consumer= american()

不難理解,漢堡的消費者可以是美國人,也可以是現代人,更可以是人類。

因此,對於 in 泛型,我們能夠將使用父類泛型的物件賦值給使用子類泛型的物件。

反之,如果我們修改如下,就會出現錯誤,因為漢堡的消費者不僅僅是美國人或現代人。

val consumer1 : consumer= everybody()

val consumer2 : consumer= modernpeople() // error

val consumer3 : consumer= american() // error

Kotlin 泛型中的 in 和 out

簡評 在 kotlin 中使用泛型你會注意到其中引入了 in 和 out,對於不熟悉的開發者來說可能有點難以理解。從形式上講,這是一種定義逆變和協變的方式,這篇文章就來講講怎麼來理解和記住它們。out 協變 如果你的類是將泛型作為內部方法的返回,那麼可以用 out inte ce productio...

Kotlin 泛型中的 in 和 out

簡評 在 kotlin 中使用泛型你會注意到其中引入了 in 和 out,對於不熟悉的開發者來說可能有點難以理解。從形式上講,這是一種定義 逆變和協變的方式,這篇文章就來講講怎麼來理解和記住它們。in out 怎麼記?out 協變 如果你的類是將泛型作為內部方法的返回,那麼可以用 out inte ...

Kotlin筆記之泛型(一)

泛型類和函式 型別引數約束 泛型允許定義帶型別形參的型別,當這種型別的例項被建立出來的時候,型別形參被替換成稱為型別實參的具體型別 例項 原始碼listof函式宣告 funlistof vararg elements t list val list listof hello world 編譯器推導 ...