Kotlin:如何避免密封类到带泛型子类的未检查转换?
解决密封类泛型子类的未检查类型转换问题
我之前也碰到过一模一样的问题,核心原因在于你的密封类State本身没有绑定泛型参数,导致子类Load<T>、Data<T>的泛型信息在父类层面被类型擦除了——编译器没法确认你在LoadableContentController<T>里拿到的Load实例的泛型T,和Controller的T是同一个类型,所以会抛出未检查类型转换的警告。
下面是两种靠谱的解决思路,优先推荐第一种:
方案一:给密封类State添加泛型参数
这是最直接且类型安全的做法,让整个状态体系的泛型约束统一起来,编译器就能全程追踪T的类型:
// 给密封类添加泛型T sealed class State<T> // Empty状态用Nothing作为泛型,因为它不需要携带数据 object Empty : State<Nothing>() class Load<T>(val presentable: Presentable<T>) : State<T>() class Data<T>(val presentable: Presentable<T>) : State<T>() class LoadableContentController<T>( private val presenter: LoadableContentPresenter<T> ) { // 现在state的类型是State<T>,和Controller的泛型绑定 private var state: State<T> = Empty fun present(content: Presentable<T>?) { when (state) { is Empty -> { // 处理空状态逻辑 } is Load<T> -> { // 这里直接访问state.presentable,类型是Presentable<T>,完全安全 presenter.handleLoad(state.presentable) } is Data<T> -> { presenter.handleData(state.presentable) } } } }
这样修改后,所有的类型转换都是编译器可验证的,不会再有未检查转换的警告,而且代码的可读性和安全性都提升了。
方案二:保留无泛型密封类,用reified泛型辅助类型检查
如果因为某些原因不想给State加泛型,可以用Kotlin的reified内联函数来做类型安全检查,不过这种写法相对繁琐:
sealed class State object Empty : State() class Load<T>(val presentable: Presentable<T>) : State() class Data<T>(val presentable: Presentable<T>) : State() class LoadableContentController<T>( private val presenter: LoadableContentPresenter<T> ) { private var state: State = Empty inline fun <reified T> State.asLoad(): Load<T>? { return this as? Load<T> } inline fun <reified T> State.asData(): Data<T>? { return this as? Data<T> } fun present(content: Presentable<T>?) { when (state) { is Empty -> { /* 处理空状态 */ } else -> { state.asLoad<T>()?.let { loadState -> presenter.handleLoad(loadState.presentable) } ?: state.asData<T>()?.let { dataState -> presenter.handleData(dataState.presentable) } } } } }
这种方法通过reified泛型在运行时保留类型信息,避免了未检查转换的警告,但不如第一种方案简洁直观,所以更推荐第一种。
内容的提问来源于stack exchange,提问作者Elye
相关产品推荐
相关产品推荐

