Kotlin 1.2按子类型/泛型过滤集合且兼容Java的实现问题
问题根因
这个报错不是Kotlin 1.2的固有局限,是你原有的函数签名泛型约束设计不合理导致的:
- 原签名要求泛型参数
S必须是Setting<V>的子类型,而Kotlin泛型默认是不变的,Setting<*>是投影类型,和Setting<Any>不属于子类型关系 - 当你传入
Setting::class.java时,S会被推断为Setting<*>,无法匹配到符合约束的V参数,因此触发类型推导失败的报错
解决方案
调整函数签名,解除S和V的强绑定约束,把值类型校验逻辑放到函数内部实现即可,同时可以兼顾Java调用兼容性:
1. 基础实现(兼容Java调用)
fun <S : Setting<*>> Iterable<Setting<*>>.filterByType( settingType: Class<S>, valueType: Class<*>? = null ) : List<S> { return filter { entry -> // 先匹配Setting的类型,再匹配值类型(如果传了valueType的话) settingType.isInstance(entry) && (valueType == null || valueType.isInstance(entry.value)) }.map { settingType.cast(it) } }
这个版本Java可以直接调用,原有正常的调用逻辑不需要修改,同时支持根类型Setting的查询:
// 原有调用完全兼容 val roles = settings.filterByType(Role::class.java) val strings = settings.filterByType(StringSetting::class.java) // 原来报错的调用现在可以正常运行 val allSettings = settings.filterByType(Setting::class.java) // 还支持按值类型过滤根Setting val intSettings = settings.filterByType(Setting::class.java, Int::class.java)
2. 扩展优化(Kotlin侧使用体验升级)
如果需要简化Kotlin侧的调用,可以额外加一个inline reified的重载,这个重载只给Kotlin侧使用,不影响Java兼容性:
inline fun <reified S : Setting<*>> Iterable<Setting<*>>.filterByType( valueType: Class<*>? = null ) : List<S> = filterByType(S::class.java, valueType)
Kotlin侧可以直接用更简洁的语法调用:
val roles = settings.filterByType<Role>() val boolSettings = settings.filterByType<Setting<*>>(Boolean::class.java)
内容的提问来源于stack exchange,提问作者Matthew Layton
相关产品推荐
相关产品推荐

