首页 文章

与Kotlin仿制药混淆

提问于
浏览
3

我是Kotlin的新手,我正在尝试编写一些相当简单的代码,但是我无法弄清楚如何使用泛型来使其工作 .

我有一个 Handler 特征,代表事物的处理程序 . I cannot change the code for a Handler as it comes from a library .

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

以下所有代码均由我控制 -

User 是一个开放类,具有 AdminUserGuestUser 等子类 .

名为 AdminUserAction 的特性可以创建一个AdminUsers列表,然后将列表传递给 List<AdminUser> 的处理程序 -

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

现在我想为 User 而不是 AdminUser 传递 AdminUserAction 处理程序 . 让's say the handler simply logs the names of the users, and doesn' t对管理员特定属性执行任何操作 .

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,因为它来自一个库 . 此外,由于Handler的类型是完全通用的,并且也应该可用于其他类型的处理程序,因此看起来很麻烦 .

我尝试了子类化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>> { }

但这给了我更多的错误 .

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

Edit:

我可以通过编写将 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 的正文 . 它正在做 nothing !然而,我必须经历每次使用它的繁琐,以满足类型 .

有没有更好的办法?在技术上是否可以使Kotlin编译器更智能,以便不需要这种类型的jugglery?

1 回答

  • 1

    有几种解决方案:

    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>>)
    }
    

相关问题