Kotlin類型安全閥門:簡單理解in和out流向控制,拒絕類型翻車!
在開發中,Kotlin泛型類型的安全性就像水杯的「防燙設計」——in和out這兩個關鍵字能幫我們避免類型燙傷。
理解Kotlin中的in和out
場景一:安全的容器(out關鍵字)想象你有一個只能倒水的飲水機,這就是out的作用。我們定義飲水機接口:
interface WaterDispenser<out T> {
fun pour(): T // 只能倒水
}
class ColdWater : Water() // 冷水類型
open class Water() // 基礎水類型
// 冷水機實現
class ColdDispenser : WaterDispenser<ColdWater> {
override fun pour() = ColdWater()
}
fun main() {
// 基礎飲水機裝冷水(安全操作)
val dispenser: WaterDispenser<Water> = ColdDispenser()
val myWater: Water = dispenser.pour()
// dispenser.reload(ColdWater()) ← 會報錯!這里禁止裝水
}
關鍵點:
? 當使用out時,相當于給容器貼上「只出不進」的標簽
? 允許把冷水機當作普通飲水機使用(向上兼容)
? 禁止添加任何裝水的方法(編譯器會報錯)
場景二:智能垃圾桶(in關鍵字)現在有個只能裝垃圾的智能垃圾桶,這就是in的作用。定義垃圾處理接口:
interface TrashBin<in T> {
fun dispose(item: T)// 只能裝垃圾
}
open class Garbage // 基礎垃圾
class FoodWaste : Garbage() // 廚余垃圾
// 廚余垃圾桶實現
class FoodBin : TrashBin<FoodWaste> {
overridefun dispose(item: FoodWaste) {
println("處理廚余垃圾:${item.hashCode()}")
}
}
fun main() {
// 普通垃圾桶裝廚余垃圾(安全操作)
val bin: TrashBin<FoodWaste> = FoodBin()
bin.dispose(FoodWaste())
// val found = bin.retrieve() ← 會報錯!禁止取垃圾
}
關鍵點:
- ?in相當于「只進不出」的封印
- ? 允許處理更具體的垃圾類型(向下兼容)
- ? 禁止任何取垃圾的操作(編譯保護)
類型安全的三把鑰匙
生產消費模型:
? 生產者用out(如數據讀取器)
interface DataReader<out T> {
fun readNext(): T
}
? 消費者用in(如數據處理器)
interface DataProcessor<in T> {
fun process(input: T)
}
集合操作示例
fun copyData(src: List<out String>, dest: MutableList<in String>) {
for (item in src) {
dest.add(item) // 安全操作:src只讀,dest只寫
}
}
錯誤規避指南
錯誤場景 | 編譯器提示 |
在out類型中嘗試寫入 | Type mismatch 錯誤 |
在in類型中嘗試讀取 | Cannot access 'XXX' 錯誤 |
混用泛型修飾符 | Conflicting variance 錯誤 |
為什么需要方向控制?
? 防止數據污染:就像不能把臟水倒回飲水機
? 提升代碼彈性:冷水機可以當作普通飲水機使用
? 編譯期類型檢查:在寫代碼時就發現問題,避免運行時崩潰
總結就是:
? 向外拿用out(輸出數據)
? 往里塞用in(輸入數據)
? 泛型箭頭方向:out相當于? extends T,in相當于? super T
通過控制數據流向,in和out就像給代碼加上智能閥門。記住:當需要安全地處理繼承關系中的類型轉換時,這兩個關鍵字就是你的類型安全衛士。下次寫泛型時,先問自己:這個容器是用來取東西還是裝東西的?