Kotlin中如何让枚举存储的返回类型直接呈现真实KClass类型而非KClass<*>
Kotlin中如何让枚举存储的返回类型直接呈现真实KClass类型而非KClass<*>
这个问题确实说到了Kotlin枚举的一个小局限——枚举类本身没法携带泛型参数,所以你定义的returnType只能统一是KClass<*>,编译器没法自动识别每个枚举条目对应的具体类型。不过我们可以用密封类来替代枚举,完美解决这个问题,同时还能保留枚举那种“有限固定实例”的特性。
具体实现方案
我们可以把原来的枚举改成带泛型的密封类,每个规则对应密封类的一个对象子类,每个子类都明确指定自己的泛型类型:
// 用密封类替代枚举,每个子类携带具体的类型信息 sealed class Rule<T>(val returnType: KClass<T>) { object A : Rule<Boolean>(Boolean::class) object B : Rule<Int>(Int::class) // 若你需要Java的Integer类型,可替换为Integer::class }
这样一来,当你访问Rule.A.returnType时,编译器会自动推断出它的类型是KClass<Boolean>,完全不用手动强转!
适配你的规则引擎
接下来调整你的Evaluator接口,让它接收带泛型的Rule<T>参数,这样调用时就能自动推断返回类型:
interface Evaluator { operator fun <T> invoke(rule: Rule<T>): T }
现在使用的时候就不用再手动指定泛型类型了,代码会简洁很多,而且类型安全:
fun createEvaluatorX(process: Evaluator) = when (process(Rule.A)) { // 自动推断返回Boolean类型 true -> when (process(Rule.B)) { // 自动推断返回Int类型 1 -> // 处理逻辑 2 -> // 处理逻辑 else -> // 处理逻辑 } false -> // 处理逻辑 }
为什么不用枚举?
Kotlin的枚举类是同构的——所有枚举条目都是同一个枚举类的实例,所以它们的属性类型必须统一。你没法让Rule.A的returnType是KClass<Boolean>,同时让Rule.B的returnType是KClass<Int>,因为枚举类的属性类型只能定义一次。而密封类的子类可以各自携带不同的泛型参数,正好满足我们“每个规则对应不同返回类型”的需求。
如果某些场景下你一定要用枚举,也有个折中方案:给枚举添加一个带reified泛型的扩展函数来返回具体类型,但调用时还是得手动指定类型,本质上绕不开额外的类型声明,所以更推荐用密封类的方案。
备注:内容来源于stack exchange,提问作者Jacob van Lingen
相关产品推荐
相关产品推荐

