Kotlin密封类泛型编译失败:类型检查报错及解决方案问询
咱们先把问题拆解清楚,你遇到的编译错误和类型擦除有关,但直接触发报错的是Kotlin对泛型类的类型检查规则:
为什么doIfFailure能正常工作?
ResultOf.Failure是一个无泛型参数的内部类,所以你直接写this is ResultOf.Failure时,编译器能明确识别这个具体类型,没有任何歧义,自然可以正常编译。
为什么doIfSuccess编译失败?
ResultOf.Success是一个带泛型参数的内部类,Kotlin不允许使用“裸类型”(也就是不带类型参数的泛型类名称)进行类型检查。你写的ResultOf.Success没有指定任何类型参数,违反了这个规则,所以编译器才会提示“One type argument expected”。
这里和类型擦除的关联在于:泛型类的类型参数在运行时会被擦除,但Kotlin在编译阶段就会强制要求你明确泛型类的类型参数——要么指定具体类型,要么用通配符*表示任意类型,不允许裸用泛型类名。
无需修改ResultOf的解决办法
完全不需要给ResultOf本身添加泛型参数,只需要调整doIfSuccess的类型检查逻辑,利用你已经用到的reified特性即可:
inline fun <reified T> ResultOf.doIfSuccess(callback: (value: T) -> Unit) { // 明确指定泛型参数为T,结合reified保留类型信息 if (this is ResultOf.Success<T>) { callback(value) } }
原理说明:
因为你用了inline fun <reified T>,Kotlin会在编译期将内联函数的代码直接插入调用位置,并且保留T的具体类型信息。这时候this is ResultOf.Success<T>的类型检查是有效的——编译器会在编译阶段验证当前实例是否为泛型参数恰好是T的Success对象,匹配成功后,value会被智能转换为T类型,完美适配回调函数的参数要求。
如果你的需求是兼容任意类型的Success(比如回调参数接受Any?),也可以用通配符实现:
inline fun ResultOf.doIfSuccess(callback: (value: Any?) -> Unit) { if (this is ResultOf.Success<*>) { callback(value) } }
内容的提问来源于stack exchange,提问作者enyciaa

