2-2-16 快速掌握Kotlin-泛型扩展函数

Kotlin 语言中泛型的扩展函数

在 Kotlin 中,我们可以为泛型类型(包括具体的泛型类和泛型参数)定义扩展函数,这提供了极大的灵活性。

1. 为泛型类定义扩展函数

基本语法

kotlin 复制代码
// 为 List<T> 定义扩展函数
fun <T> List<T>.customFilter(predicate: (T) -> Boolean): List<T> {
    return this.filter(predicate)
}

// 为 MutableList<T> 定义扩展函数
fun <T> MutableList<T>.removeIf(predicate: (T) -> Boolean): Boolean {
    val iterator = this.iterator()
    var removed = false
    while (iterator.hasNext()) {
        if (predicate(iterator.next())) {
            iterator.remove()
            removed = true
        }
    }
    return removed
}

// 使用
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.customFilter { it % 2 == 0 }  // [2, 4]

2. 带有类型约束的泛型扩展函数

使用上界约束

kotlin 复制代码
// 只有实现了 Comparable 的类型才能使用这个扩展
fun <T : Comparable<T>> List<T>.sortedDescending(): List<T> {
    return this.sortedDescending()
}

// 多个约束
fun <T> List<T>.sumByIfNumber(selector: (T) -> Number): Double 
    where T : Any, T : Comparable<T> {
    return this.sumOf { selector(it).toDouble() }
}

// 使用
val numbers = listOf(1, 2, 3)
println(numbers.sortedDescending())  // [3, 2, 1]

val items = listOf("a", "bb", "ccc")
// 错误:String 没有实现 Number 接口
// println(items.sumByIfNumber { it.length }) 

3. 协变(out)和逆变(in)的扩展函数

协变扩展函数

kotlin 复制代码
// 为协变类型定义扩展函数
fun <T> List<out T>.safeFirstOrNull(): T? {
    return this.firstOrNull()
}

// 使用协变参数
interface Producer<out T> {
    fun produce(): T
}

fun <T> Producer<T>.produceMultiple(times: Int): List<T> {
    return List(times) { this.produce() }
}

逆变扩展函数

kotlin 复制代码
// 为逆变类型定义扩展函数
interface Consumer<in T> {
    fun consume(item: T)
}

fun <T> Consumer<T>.consumeAll(items: List<T>) {
    items.forEach { this.consume(it) }
}

4. reified 泛型扩展函数

结合 reified 关键字,可以在运行时访问泛型类型信息:

kotlin 复制代码
// 检查集合中的所有元素都是指定类型
inline fun <reified T> List<*>.allOfType(): Boolean {
    return this.all { it is T }
}

// 从 JSON 字符串解析为指定类型
inline fun <reified T> String.fromJson(): T? {
    // 使用 Gson 或其他 JSON 库
    return try {
        // 假设有 gson 实例可用
        gson.fromJson(this, T::class.java)
    } catch (e: Exception) {
        null
    }
}

// 使用
val mixedList = listOf(1, 2, "3", 4)
println(mixedList.allOfType<Int>())  // false

val json = """{"name": "John", "age": 30}"""
val person = json.fromJson<Person>()  // 自动推断类型

5. 为泛型对(Pair/Triple)定义扩展函数

kotlin 复制代码
// 为 Pair 定义扩展函数
fun <A, B> Pair<A, B>.swap(): Pair<B, A> {
    return Pair(second, first)
}

fun <A, B, C> Triple<A, B, C>.rotate(): Triple<C, A, B> {
    return Triple(third, first, second)
}

// 为两个相同类型的 Pair 定义扩展函数
fun <T : Comparable<T>> Pair<T, T>.sorted(): Pair<T, T> {
    return if (first <= second) this else swap()
}

// 使用
val pair = Pair("hello", 123)
val swapped = pair.swap()  // Pair(123, "hello")

val numbers = Pair(5, 3)
val sorted = numbers.sorted()  // Pair(3, 5)

6. 高阶泛型扩展函数

接受函数参数的泛型扩展

kotlin 复制代码
// 为 Sequence<T> 定义扩展函数
fun <T, R> Sequence<T>.mapWithIndex(
    transform: (index: Int, T) -> R
): Sequence<R> = sequence {
    var index = 0
    for (item in this@mapWithIndex) {
        yield(transform(index++, item))
    }
}

// 为 Iterable<T> 定义扩展函数
fun <T, K, V> Iterable<T>.associateByMany(
    keySelector: (T) -> K,
    valueTransform: (T) -> V
): Map<K, List<V>> {
    val result = mutableMapOf<K, MutableList<V>>()
    for (element in this) {
        val key = keySelector(element)
        val list = result.getOrPut(key) { mutableListOf() }
        list.add(valueTransform(element))
    }
    return result
}

// 使用
val names = listOf("Alice", "Bob", "Charlie", "Alice")
val map = names.associateByMany(
    keySelector = { it.first().uppercaseChar() },
    valueTransform = { it.length }
)
// 结果: {'A': [5, 5], 'B': [3], 'C': [7]}

7. 泛型扩展属性

kotlin 复制代码
// 泛型扩展属性
val <T> List<T>.midElement: T?
    get() = if (isEmpty()) null else this[size / 2]

// 带有类型约束的泛型扩展属性
val <T : Comparable<T>> List<T>.isSorted: Boolean
    get() = this.sorted() == this

// 可空泛型扩展属性
val <T> Collection<T>?.sizeOrZero: Int
    get() = this?.size ?: 0

// 使用
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers.midElement)  // 3
println(numbers.isSorted)    // true

val nullableList: List<Int>? = null
println(nullableList.sizeOrZero)  // 0

8. 实际应用示例

网络请求处理

kotlin 复制代码
// Retrofit 响应处理
sealed class ApiResult<out T> {
    data class Success<T>(val data: T) : ApiResult<T>()
    data class Error(val exception: Exception) : ApiResult<Nothing>()
}

// 为 ApiResult 定义扩展函数
fun <T> ApiResult<T>.onSuccess(block: (T) -> Unit): ApiResult<T> {
    if (this is ApiResult.Success) {
        block(this.data)
    }
    return this
}

fun <T> ApiResult<T>.onError(block: (Exception) -> Unit): ApiResult<T> {
    if (this is ApiResult.Error) {
        block(this.exception)
    }
    return this
}

// 映射结果
fun <T, R> ApiResult<T>.map(transform: (T) -> R): ApiResult<R> {
    return when (this) {
        is ApiResult.Success -> ApiResult.Success(transform(this.data))
        is ApiResult.Error -> this
    }
}

// 使用
apiService.getUser()
    .onSuccess { user ->
        updateUI(user)
    }
    .onError { error ->
        showError(error)
    }

集合处理工具

kotlin 复制代码
// 安全转换集合类型
fun <T, R : Any> Iterable<T>.mapNotNull(
    transform: (T) -> R?
): List<R> {
    return this.mapNotNull(transform)
}

// 分组并排序
fun <T, K> List<T>.groupBySorted(
    keySelector: (T) -> K,
    sortKeys: Comparator<K>? = null
): Map<K, List<T>> {
    val map = this.groupBy(keySelector)
    return if (sortKeys != null) {
        map.toSortedMap(sortKeys)
    } else {
        map
    }
}

// 查找重复项
fun <T> Iterable<T>.findDuplicates(): Set<T> {
    val seen = mutableSetOf<T>()
    val duplicates = mutableSetOf<T>()
    for (item in this) {
        if (!seen.add(item)) {
            duplicates.add(item)
        }
    }
    return duplicates
}

// 使用
val items = listOf(1, 2, 2, 3, 3, 3, 4)
val duplicates = items.findDuplicates()  // [2, 3]

9. DSL 构建中的泛型扩展

kotlin 复制代码
// 构建类型安全的 DSL
class Table<out T> {
    private val rows = mutableListOf<T>()
    
    fun row(init: RowBuilder<T>.() -> Unit) {
        val builder = RowBuilder<T>().apply(init)
        rows.add(builder.build())
    }
    
    fun getRows(): List<T> = rows
}

class RowBuilder<T> {
    var data: T? = null
    
    fun build(): T {
        return data ?: throw IllegalStateException("Row data not set")
    }
}

// 泛型扩展函数来创建表
fun <T> createTable(init: Table<T>.() -> Unit): Table<T> {
    return Table<T>().apply(init)
}

// 使用
data class Person(val name: String, val age: Int)

val table = createTable<Person> {
    row {
        data = Person("Alice", 30)
    }
    row {
        data = Person("Bob", 25)
    }
}

10. 约束类型参数的复杂场景

kotlin 复制代码
// 多个约束和类型参数
interface Identifiable<ID> {
    val id: ID
}

interface Timestamped {
    val createdAt: Long
}

// T 必须同时实现 Identifiable 和 Timestamped
fun <T, ID> List<T>.findById(id: ID): T? 
    where T : Identifiable<ID>, T : Timestamped {
    return this.find { it.id == id }
}

// 使用扩展函数进行排序
fun <T, ID> List<T>.sortByCreationTime(): List<T> 
    where T : Identifiable<ID>, T : Timestamped {
    return this.sortedBy { it.createdAt }
}

11. 性能优化考虑

kotlin 复制代码
// 内联泛型扩展函数以减少开销
inline fun <T, R> List<T>.mapInline(
    crossinline transform: (T) -> R
): List<R> {
    val result = ArrayList<R>(this.size)
    for (item in this) {
        result.add(transform(item))
    }
    return result
}

// 避免不必要的对象创建
fun <T> Iterable<T>.forEachIndexed(
    action: (index: Int, T) -> Unit
) {
    var index = 0
    for (item in this) {
        action(index++, item)
    }
}

12. 与 Java 互操作

kotlin 复制代码
// 为 Java 集合定义扩展函数
fun <T> java.util.ArrayList<T>.addIfNotNull(element: T?) {
    element?.let { this.add(it) }
}

// 处理 Java 原始类型
fun <T> Array<T>.toImmutableList(): List<T> {
    return this.toList()
}

// 使用注解改善互操作性
@JvmName("filterStrings")
fun List<String>.filterLongStrings(): List<String> {
    return this.filter { it.length > 5 }
}

最佳实践总结

  1. 保持简洁:泛型扩展函数应该专注于单一职责
  2. 明确命名:名称应该清晰地表达函数的功能
  3. 合理约束:使用类型约束确保类型安全,但不要过度约束
  4. 考虑性能 :对于高频使用的函数,考虑使用 inline
  5. 提供文档:复杂泛型扩展应该包含文档说明
  6. 避免冲突:确保扩展函数不会与现有函数冲突
  7. 测试覆盖:泛型扩展函数应该被充分测试

泛型扩展函数是 Kotlin 中非常强大的特性,它们可以帮助您创建更通用、更类型安全且更易用的 API。

相关推荐
I'm Jie6 小时前
Gradle 多模块依赖集中管理方案,Version Catalogs 详解(Kotlin DSL)
android·java·spring boot·kotlin·gradle·maven
BoomHe6 小时前
Android 13 (API 33)开发自己的 Settings ,如何配置 WiFi BT 权限
android
城东米粉儿6 小时前
ConcurrentHashMap实现原理 笔记
android
佳哥的技术分享6 小时前
System.setProperty vs adb setprop (Android SystemProperties)
android·adb
Railshiqian7 小时前
通过adb命令获取某个window或View/子View的绘制内容并输出为png图片的方法
android·adb·dump view
XI锐真的烦7 小时前
新手该如何选择 Android 开发框架?
android
走在路上的菜鸟8 小时前
Android学Dart学习笔记第二十六节 并发
android·笔记·学习·flutter
00后程序员张8 小时前
AppStoreInfo.plist 在苹果上架流程中的生成方式和作用
android·小程序·https·uni-app·iphone·webview
成都大菠萝8 小时前
2-2-10 快速掌握Kotlin-out协变
android