Kotlin中如何将Object定义为泛型密封类的子类型?
解决方案:将
UserNotRecognized改为单例object并兼容泛型密封类 要实现把UserNotRecognized从带泛型的data class改成单例object,核心需要解决泛型兼容的问题——因为object不能声明泛型参数,而父密封类SubscriptionServiceResponse<T>是带泛型的。下面是具体实现步骤和代码:
1. 修改密封类为协变泛型
首先把密封类的泛型标记为out(协变),这样我们可以用Nothing类型来适配所有可能的泛型场景:
sealed class SubscriptionServiceResponse<out T>
out关键字表示这个泛型类型是生产型的,只能向外提供数据而不能消费,这符合响应类的场景,同时允许子类的泛型类型是父类泛型的子类型。
2. 定义单例UserNotRecognized
让UserNotRecognized实现SubscriptionServiceResponse<Nothing>——Nothing是Kotlin中所有类型的子类型,结合协变泛型,这个单例可以被当作任何SubscriptionServiceResponse<T>来使用:
object UserNotRecognized : SubscriptionServiceResponse<Nothing>() { // 如果需要保留原来的ignored参数,直接把它作为单例的属性即可 val ignored: Boolean = true }
3. 保留UserRecognized的实现
UserRecognized作为带具体数据的响应类,依然保持原来的data class实现即可:
data class UserRecognized<T>(val recognizedUser: RecognizedUser, val response: T) : SubscriptionServiceResponse<T>()
使用示例
在处理响应的when表达式中,你可以无缝使用这个单例,类型系统会自动兼容:
fun processResponse(response: SubscriptionServiceResponse<String>) { when (response) { is UserRecognized -> { println("识别到用户:${response.recognizedUser},响应数据:${response.response}") } UserNotRecognized -> { println("用户未识别,ignored状态:${UserNotRecognized.ignored}") } } }
为什么这样可行?
object不能有泛型参数,所以我们必须给它指定一个具体的泛型类型,Nothing是最优选择,因为它是所有类型的子类型。- 协变泛型
out T让SubscriptionServiceResponse<Nothing>可以安全地赋值给任何SubscriptionServiceResponse<T>,完全适配你原来的代码场景。
内容的提问来源于stack exchange,提问作者david.mihola
相关产品推荐
相关产品推荐

