在Kotlin中混合类和函数泛型?

我试图创建一个接口,定义一个单一的方法。 该方法的参数类型必须是接口的类型参数,因为接口的实现将具有唯一的此参数实现。 到目前为止,罚款是,该参数也有一个类型的参数是绑定到该方法。 我可以有一个类型参数定义为一个类类型参数,它也有自己的类型参数绑定到该方法?

换句话说:

我试图建立一个API实现两个客户端接口。 每个客户端根据传递到它们的rxecute函数的Request<T>对象(RxJava +执行,是的,我过分地为这个名字感到骄傲)进行api调用。

我的问题是如何在界面中定义rxecute方法。 让我列出一些示例代码(我的实际代码是不使用impl ,不用担心)。

 interface Request<T> // T is return type of the request class RequestImpl<T>: Request<T> { // impl } interface ApiClient<R : Request<*>> { // R should somehow be of type Request<T> fun <T> rxecute(request: R): Single<T> } class ApiClientImpl : ApiClient<RequestImpl<????>> { override fun <T> rxecute(request: RequestImpl<T>): Single<T> = // impl } 

我想能够像这样使用它:

 val apiClient = ApiClientImpl() apiClient.rxecute(RequestImpl<SomeClass>()).subscribe(someClassResult -> ...) 

是否有可能创建一个这样的界面或泛型不工作?

不幸的是,Kotlin的仿制药不能以这种方式操纵, 一个类型参数R不能作为一个通用类型本身( R<T> ),它的上界在声明站点是固定的,你只能使用一个类型参数R作为单一的上界(无法添加另一个where Q : R, Q : Request<T>不起作用)。

你只能参数化具体类型,而我想到的一个选择是递归泛型模式(它也用于Java)。 您可以将实现类型的另一个类型参数添加到Request ,以使其成为interface Request<R, T> 。 这要求您将实现的类型添加到继承的类型声明中:

 class RequestImpl<T>: Request<RequestImpl<*>, T> { /* impl */ } 

然后修改ApiClient

 interface ApiClient<R : Request<R, *>> { fun <T> rxecute(request: Request<R, T>): Single<T> } 

这里出现的不受欢迎的副作用是,您需要将request as RequestImpl作为RequestImplrequest as RequestImpl使用。

并转换ApiClientImpl如下:

 class ApiClientImpl : ApiClient<RequestImpl<*>> { override fun <T> rxecute(request: Request<RequestImpl<*>, T>): Single<T> = TODO() } 

这个解决方案看起来比你所要求的要冗长得多,但对于这种情况,递归泛型似乎是一种常见的解决方法,它需要比Java和Kotlin所能提供的更强大的类型系统。


(在答案中的代码的可运行演示)