Kotlin:求助实现无需额外占位符的协变容器类型参数拓宽扩展函数
Kotlin:求助实现无需额外占位符的协变容器类型参数拓宽扩展函数
嘿,我完全懂你的感受——那俩下划线真的太破坏API的流畅性了,做库就是要让用户用得顺手,这种小细节确实闹心!
其实咱们可以通过调整泛型参数的约束或者利用Kotlin的协变特性来解决这个问题,给你两个实用的方案:
方案一:利用协变特性实现无转换的拓宽
因为Kotlin的List本身就是协变的(定义为List<out E>),我们可以直接基于协变的接收者来写扩展函数,只需要指定目标类型U就行:
fun <U> List<out U>.widen(): List<U> = this
使用方式
val listOfInts = listOf(1,2,3,4,5) // 方式1:通过变量类型自动推断U val listOfNumbers: List<Number> = listOfInts.widen() // 方式2:显式指定目标类型 val listOfNumbers = listOfInts.widen<Number>()
这个方案不需要任何强制转换,完全利用Kotlin的类型系统特性,既安全又简洁。
方案二:reified类型参数+安全转换(兼容更多场景)
如果你的场景中接收者的类型没法直接匹配List<out U>,可以用reified类型参数配合安全转换,同样只需要指定目标类型:
inline fun <reified U> List<*>.widen(): List<U> { @Suppress("UNCHECKED_CAST") return this as List<U> }
使用方式
val listOfInts = listOf(1,2,3,4,5) val listOfNumbers = listOfInts.widen<Number>() // 直接指定目标类型即可
这里的转换是安全的,因为List是只读协变容器,你没法往里面添加不符合U类型的元素,不会出现运行时类型异常。
为什么原来的写法需要下划线?
你原来的函数fun <U:Any,T:U> List<T>.widen():List<U> = this需要指定两个类型参数,是因为编译器需要同时确定U和T,当你只指定U时,编译器有时候没法自动推断T(尤其是在上下文类型不明确的时候)。而上面的两个方案都只需要让你指定目标类型U,T要么通过协变约束自动匹配,要么通过List<*>兼容所有子类型,完美避开了这个问题。
这样应该就能让你的库API保持清爽啦!
备注:内容来源于stack exchange,提问作者caeus
相关产品推荐
相关产品推荐

