You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:52:44