Kotlin泛型进阶:如何构建非平凡类型关联?(遇Nothing类型不匹配)
Kotlin泛型实现基于类型的事件分发器解决方案
问题背景
我要构建一个处理应用内事件的简易API,把事件信息发送到不同目标,采用基于类型的设计——通过事件子类型确定事件处理器的发送目标。
示例代码定义了AppEvent、Sender等接口及实现类,期望事件可以混合多个...able接口来匹配对应的Sender。但编写Dispatcher时遇到泛型问题,两处实现都在senders.forEach { it.send(event) }处出现编译错误:Type mismatch. Required: Nothing Found: Any。
我已经用Java的extends和super实现了相同逻辑,现在需要Kotlin泛型的正确实现方式,同时希望了解详细的Kotlin泛型用法。
补充需求:Dispatcher要实现部分运行时类型安全,流程如下:
- 获取Sender可处理的类型(比如
Loggable); - 检查事件是否实现该类型或具备所需特征;
- 匹配后通过类型转换或重新包装传递事件,要求在保留调用代码约束的前提下放松类型检查。
解决方案
1. 修正Sender接口泛型约束
使用Kotlin的in关键字实现逆变(对应Java的? super T),确保Sender可以接受其泛型类型的父类实例,同时添加方法用于获取可处理的类型,支持运行时检查:
interface Sender<in T> { fun send(event: T) fun getHandledType(): Class<out T> }
2. 实现Dispatcher逻辑
Dispatcher通过星号投影存储任意类型的Sender,分发时做运行时类型校验和安全转换:
class Dispatcher { private val senders = mutableListOf<Sender<*>>() fun registerSender(sender: Sender<*>) { senders.add(sender) } fun dispatch(event: Any) { senders.forEach { sender -> val handledType = sender.getHandledType() // 运行时校验事件是否匹配Sender可处理类型 if (handledType.isInstance(event)) { // 已通过运行时校验,使用unchecked cast放松编译期检查 @Suppress("UNCHECKED_CAST") (sender as Sender<Any>).send(event) } } } }
3. 事件与Sender示例代码
定义事件基类、标记接口及混合类型事件:
interface AppEvent interface Loggable : AppEvent { fun getLogContent(): String } interface Notifiable : AppEvent { fun getNotificationMessage(): String } // 同时实现多个标记接口的事件类 class UserCreatedEvent( val userId: String, val userName: String ) : Loggable, Notifiable { override fun getLogContent() = "User created: $userId - $userName" override fun getNotificationMessage() = "New user $userName joined!" }
实现具体的Sender处理器:
class LogSender : Sender<Loggable> { override fun send(event: Loggable) { println("Log: ${event.getLogContent()}") } override fun getHandledType() = Loggable::class.java } class NotificationSender : Sender<Notifiable> { override fun send(event: Notifiable) { println("Notification: ${event.getNotificationMessage()}") } override fun getHandledType() = Notifiable::class.java }
4. 调用示例
fun main() { val dispatcher = Dispatcher() dispatcher.registerSender(LogSender()) dispatcher.registerSender(NotificationSender()) val event = UserCreatedEvent("1", "Alice") dispatcher.dispatch(event) // 输出: // Log: User created: 1 - Alice // Notification: New user Alice joined! }
Kotlin泛型核心要点
- 逆变(
in关键字):当泛型参数仅作为输入(如Sender的send方法参数)时,使用in允许接受泛型类型的父类实例,对应Java的? super T。 - 星号投影(
*):Sender<*>表示任意泛型类型的Sender实例,适用于不需要关心具体泛型类型的场景。 - 运行时类型校验:通过
isInstance和::class.java做运行时类型检查,配合@Suppress("UNCHECKED_CAST")可安全放松编译期类型约束,前提是已完成运行时校验。
内容的提问来源于stack exchange,提问作者Ondra Žižka
相关产品推荐
相关产品推荐

