Kotlin中的泛型:为什么需要以及如何实际使用

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Kotlin中的泛型:为什么需要以及如何实际使用



泛型是Kotlin语言的关键特性之一,它允许编写更灵活、类型安全且可重用的代码。如果你曾经写过List<String>或Map<Int, User>,那么你已经接触过泛型。但它们实际上为什么需要,以及如何充分利用它们?在本文中,我们将分析理论,并通过实际示例进入实践。



泛型解决的问题



假设你需要编写一个函数,返回列表中的第一个元素。没有泛型,你必须为每种数据类型编写单独的函数:



fun getFirstString(list: List<String>): String? = list.firstOrNull()fun getFirstInt(list: List<Int>): Int? = list.firstOrNull()fun getFirstUser(list: List<User>): User? = list.firstOrNull()


这会导致代码重复。使用Any可以解决问题,但你会丢失编译时的类型信息:



fun getFirst(list: List<Any>): Any? = list.firstOrNull()

// 必须进行类型转换val name: String? = getFirst(strings) as? String


泛型优雅地解决了这个问题:



fun <T> getFirst(list: List<T>): T? = list.firstOrNull()

// 编译器知道类型!val name: String? = getFirst(listOf("Alice", "Bob"))val age: Int? = getFirst(listOf(25, 30))


现在一个函数可以处理任何类型,同时保持完全的类型安全。



Kotlin中泛型的基础:语法和声明



泛型使用尖括号<T>声明。字母T只是一个约定,你可以使用任何名称:E(元素)、K(键)、V(值)。



泛型类



class Box<T>(val value: T) {    fun getContent(): T = value}

fun main() { val stringBox = Box("Hello") val intBox = Box(42) println(stringBox.getContent()) // Hello println(intBox.getContent()) // 42}


泛型函数



fun <T> printItem(item: T) {    println("Item: $item")}

// 可以显式指定类型printItem<String>("Kotlin")// 或者依赖类型推断printItem(100)


泛型接口



interface Repository<T> {    fun getById(id: Int): T    fun save(item: T): Boolean}

class UserRepository : Repository<User> { override fun getById(id: Int): User { /* ... */ } override fun save(item: User): Boolean { /* ... */ }}


变型:in、out和星号*



Kotlin最强大的特性之一是变型。它回答的问题是:List<String>可以是List<Any>的子类型吗?



协变(out)



当你的泛型类型只被返回(生产者)时,使用out。例如,List<T>是协变的:



// 你可以将List<String>赋值给List<Any>变量val strings: List<String> = listOf("a", "b")val anyList: List<Any> = strings // 可以!

// 但不能添加元素// anyList.add(1) // 编译错误!


自定义示例:



class Producer<out T>(private val value: T) {    fun produce(): T = value}

fun main() { val stringProducer: Producer<String> = Producer("Hello") val anyProducer: Producer<Any> = stringProducer // 可以工作! println(anyProducer.produce())}


逆变(in)



当类型只被接受(消费者)时,使用in。例如,Comparable<T>:





                
                

博客

书籍推荐