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。

相关推荐
佛系打工仔3 小时前
绘制K线第二章:背景网格绘制
android·前端·架构
my_power5206 小时前
车载安卓面试题汇总
android
csj506 小时前
安卓基础之《(15)—内容提供者(1)在应用之间共享数据》
android
yeziyfx7 小时前
kotlin中 ?:的用法
android·开发语言·kotlin
2501_915918418 小时前
只有 Flutter IPA 文件,通过多工具组合完成有效混淆与保护
android·flutter·ios·小程序·uni-app·iphone·webview
robotx8 小时前
AOSP 设置-提示音和振动 添加一个带有开关(Switch)的设置项
android
青莲8438 小时前
RecyclerView 完全指南
android·前端·面试
青莲8438 小时前
Android WebView 混合开发完整指南
android·前端·面试
龙之叶9 小时前
【Android Monkey源码解析三】- 运行解析
android
KevinWang_10 小时前
Android 的 assets 资源和 raw 资源有什么区别?
android