我是Kotlin的新手,我正在尝试编写一些相当简单的代码,但我无法弄清楚如何使用泛型来使其工作。
我有一个Handler
特征,代表事物的处理程序。 我无法更改处理程序的代码,因为它来自库 。
trait Handler<T> {
fun handle(result: T)
}
以下所有代码都在我的控制之下 -
User
是一个开放类,包含AdminUser
和GuestUser
等子类。
名为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?
答案 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>>)
}