首页 文章

在Kotlin混合类和函数泛型?

提问于
浏览
2

我正在尝试创建一个定义单个方法的接口 . 该方法的参数类型必须是接口的类型参数,因为接口的实现将具有此参数的唯一实现 . 到目前为止很好,但问题是该参数还有一个与方法绑定的类型参数 . 我可以将类型的参数定义为类类型参数,它还有自己的类型参数,该参数与方法相关联吗?

换一种方式:

我正在尝试使用两个实现构建一个api客户端接口 . 每个客户端根据传递到 rxecute 函数的 Request<T> 对象进行api调用(RxJava执行,是的,我对这个名称感到非常自豪) .

我的问题是如何在界面中定义 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 -> ...)

是否可以创建这样的界面,或者泛型不能像那样工作?

1 回答

  • 3

    不幸的是,Kotlin仿制药不能以这种方式操纵;类型参数 R 不能用作泛型类型本身( R<T> ),并且其上限在声明站点处是固定的,并且您只能使用类型参数 R 作为单个上限(无法添加另一个, where Q : R, Q : Request<T> 不起作用) .

    您只能参数化具体类型,我想到的一个选项是recursive generics模式(它也用于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>
    }
    

    这里出现的一个不受欢迎的副作用是你需要将请求转换为RequestImpl:request请求作为RequestImpl .

    并转换 ApiClientImpl 如下:

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

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


    (runnable demo of the code in the answer)

相关问题