与Kotlin仿制药混淆

时间:2015-05-01 09:25:41

标签: java generics types type-conversion kotlin

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

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

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

以下所有代码都在我的控制之下 -

User是一个开放类,包含AdminUserGuestUser等子类。

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

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

现在我想为AdminUserAction而不是User传递一个AdminUser处理程序。假设处理程序只记录用户的名称,并且不对管理员特定属性执行任何操作。

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的类型是完全通用的,并且也应该可用于其他类型的处理程序。

我尝试了继承Handler并使用它 -

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

但是现在我收到一个错误,上面写着“参数T被声明为'in'但是出现在Handler&gt;中的'invariant'位置”

我试过了 -

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编译器更智能,以便不需要这种类型的jugglery?

1 个答案:

答案 0 :(得分: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>>)
}