如何为拥有协变返回类型方法的类型层级编写Kotlin泛型扩展方法
如何为拥有协变返回类型方法的类型层级编写Kotlin泛型扩展方法
这个问题的核心在于:虽然你在子类里重写map()时返回了具体子类型,但接口定义里map()的返回值是MyInterface,泛型扩展的<T : MyInterface>约束不足以让编译器推断出map()的返回值就是T——它只能确定返回的是MyInterface的某个子类,但没法和当前的T划等号。
给你两种解决方案,优先推荐第一种编译期安全的方式:
方案一:给接口添加自类型泛型约束
我们可以修改原接口,通过泛型参数把map()的返回类型和实现类自身绑定起来,让编译器能明确关联类型关系:
sealed interface MyInterface<T : MyInterface<T>> { fun map(): T class ImplA : MyInterface<ImplA> { override fun map(): ImplA = ImplA() } class ImplB : MyInterface<ImplB> { override fun map(): ImplB = ImplB() } }
然后你的扩展方法只需要调整泛型约束,就能完美编译:
fun <T : MyInterface<T>> T.doThingWithMap(): T { return map() }
现在调用时,编译器能准确推断出返回类型是具体的子类:
val a: MyInterface.ImplA = MyInterface.ImplA().doThingWithMap() // 完全正常 val b: MyInterface.ImplB = MyInterface.ImplB().doThingWithMap() // 编译通过
这种方式的优势是编译期类型安全,编译器会强制要求子类实现MyInterface时指定自身作为泛型参数,同时map()必须返回该类型,从根源上避免了类型不匹配的问题。
方案二:用具体化泛型+类型转换(仅作备选)
如果因为某些限制不能修改原接口,你可以用Kotlin的reified具体化泛型配合类型转换实现,但这种方式会把类型检查推迟到运行时,存在一定风险:
inline fun <reified T : MyInterface> T.doThingWithMap(): T { // 这里需要确保所有子类的map()都确实返回自身类型,否则会抛出ClassCastException return map() as T }
这种写法不用修改原接口就能实现需求,但如果有子类没有正确重写map()返回自身(比如某个子类返回了其他实现类),运行时会直接抛出异常,所以除非万不得已,不建议使用。
备注:内容来源于stack exchange,提问作者Alex Lamaison
相关产品推荐
相关产品推荐

