Kotlin 泛型入门
泛型(通用类型)是静态类型编程语言(包括 Kotlin)的关键特性之一。它允许你编写灵活、可复用的代码来处理不同的数据类型,同时在编译时保持严格的类型安全。
假设你需要创建一个存储元素列表的数据结构。没有泛型时,你必须为每种类型编写单独的类(IntList、StringList、UserList)。有了泛型,一个单一的类 MyList<T> 就足够了,它可以适用于任何类型。
// 没有泛型 — 你必须重复代码class IntList(private val items: MutableList<Int>)class StringList(private val items: MutableList<String>)
// 使用泛型 — 一个类适用于所有类型class GenericList<T>(private val items: MutableList<T>) { fun add(item: T) { items.add(item) } fun get(index: Int): T = items[index]}在本文中,我们将深入探讨 Kotlin 中的泛型工作机制,了解其语法、使用场景以及协变和逆变等高级概念。
泛型基础
声明泛型类和函数
要声明一个泛型类,只需在类名后的尖括号中指定一个或多个类型参数:
class Box<T>(var value: T) { fun getValue(): T = value fun setValue(newValue: T) { value = newValue }}
// 使用val intBox = Box<Int>(42)val stringBox = Box<String>("Hello")
// Kotlin 可以推断类型,因此可以简写val anotherBox = Box("自动类型推断")函数也可以是泛型的。类型参数在函数名前指定:
fun <T> printItem(item: T) { println("项目: $item")}
fun <T> createPair(first: T, second: T): Pair<T, T> { return Pair(first, second)}
// 使用printItem(123)printItem("文本")val pair = createPair("A", "B")类型边界
有时你需要限制可用于泛型的类型。这时可以使用关键字 : Type 设置上界:
// 仅限实现了 Comparable 的类型fun <T : Comparable<T>> findMax(a: T, b: T): T { return if (a > b) a else b}
// 使用 where 设置多个约束fun <T> processItem(item: T) where T : CharSequence, T : Comparable<T> { println("长度: ${item.length}") println("比较结果: ${item.compareTo(item)}")}
// 使用println(findMax(10, 20)) // 20println(findMax("Apple", "Banana")) // "Banana"// findMax(10, "Text") // 编译错误!型变:in、out 和类型投影
泛型中最复杂但最重要的主题之一是型变。它定义了泛型类型在继承关系中如何相互关联。
不变性(默认)
默认情况下,Kotlin 中的泛型是不变的。这意味着 Box<Number> 和 Box<Int> 互不为子类型,即使 Int 是 Number 的子类型:
val intBox: Box<Int> = Box(42)// val numBox: Box<Number> = intBox // 编译错误!协变(out)
out 修饰符使类型变为协变。这意味着 Box<Int> 成为 Box<Number> 的子类型。当类型 T 仅用于输出位置(返回值)时使用:
class Producer<out T>(private val item: T) { fun produce(): T = item // T 仅在输出位置}