与 Kotlin 泛型的混淆

Confusion with Kotlin generics

我是 Kotlin 的新手,我正在尝试编写一些相当简单的代码,但是我不知道如何使用泛型来让它工作。

我有一个 Handler 特征,代表事物的处理程序。 我无法更改处理程序的代码,因为它来自库

trait Handler<T> {
    fun handle(result: T)
}

下面所有的代码都在我的掌控之中-

User 是一个开放的 class,它有子 class,例如 AdminUserGuestUser

一个名为 AdminUserAction 的特征会创建一个 AdminUsers 列表,然后将该列表传递给 List<AdminUser> -

的处理程序
trait AdminUserAction {
    fun then(handler: Handler<List<AdminUser>>)
}

现在我想为 User 而不是 AdminUser 传递一个 AdminUserAction 处理程序。假设处理程序只是记录用户的姓名,而不对管理员特定的属性做任何事情。

fun doIt(action: AdminUserAction, printAllNames: Handler<List<User>>) {
    action.then(printAllNames)
}

但是,这段代码给了我一个 TypeMismatch

由于 Handler 是 List<T> 类型并且是不可变的,因此前面的代码应该是完全安全的,但是编译器无法识别它。

如果我可以访问 Handler 的代码,我可以执行以下操作并且它会起作用 -

trait Handler<in T> {
    fun handle(result: T)
}

但是,正如我之前所说,我无法修改 Handler,因为它来自库。此外,似乎 hacky 必须这样做,因为 Handler 的类型是完全通用的,应该也可用于其他类型的处理程序。

我试过 subclassing Handler 并使用它 -

trait ListHandler<in T>: Handler<List<T>> { }

但是现在我收到一条错误消息 "Parameter T is declared as 'in' but occurs in 'invariant' position in Handler>"

我试过了 -

trait ListHandler<in T>: Handler<List<in T>> { }

但这给了我更多的错误。

为什么这么混乱?我如何使用泛型来使前面的代码起作用?

编辑:

我可以通过编写一个将 Handler<List<User>> 转换为 Handler<List<AdminUser>> -

的通用函数来使其工作
fun <T: User> fromGeneric(handler: Handler<User>): Handler<T> {
    return object: Handler<T> {
        override fun handle(result: List<T>) {
            handler.handle(result)
        }
    }
}

然后-

fun doIt(action: AdminUserAction, printAllNames: Handler<List<User>>) {
    action.then(fromGeneric(printAllNames))
}

但是,这看起来太浪费了。尤其要看一下转换函数的主体 fromGeneric。它什么都没做!然而,为了满足类型,我每次都必须经历使用它的繁琐程序。

有没有更好的方法?技术上是否有可能使 Kotlin 编译器更智能,从而不需要这种类型的变戏法?

有几个解决方案:

AdminUserAction的定义改为

trait AdminUserAction {
    fun then(handler: Handler<in List<AdminUser>>)
}

或将 AdminUserAction 的定义更改为

trait AdminUserAction {
    fun then(handler: Handler<List<User>>)
}

或者像这样投printAllNames

fun doIt(action: AdminUserAction, printAllNames: Handler<List<User>>) {
    action.then(printAllNames as Handler<List<AdminUser>>)
}