我可以省略泛型中的类型吗? - 科特林

Can I omit type in generics? - Kotlin

如果我有如下界面:

interface BaseDataRemote<T, in Params> {
    fun getData(params: Params? = null): Single<T>
}

是否可以实现不带参数的接口? 有效地拥有类似的东西:

interface BaseDataRemote<T> {
    fun getData(): Single<T>
}

实现如下:

class RemoteSellerDataSource @Inject constructor(
    private val sellerApi: SellerApi,
    @Named("LANG") private val lang: String
) : BaseDataRemote<SellerEntity, Nothing> {
    override fun getData(params: Nothing?): Single<SellerEntity> {
        return sellerApi.getSeller(lang).map { it.fromApiEntity() }
    }
}

我使用 Dagger 2 模块来绑定这个实现:

@Module
internal interface RemoteModule {

    @Binds
    @CoreScope
    fun bindsSellerRemote(remoteSellerDataSource: RemoteSellerDataSource): BaseDataRemote<SellerEntity, Nothing>
}

我尝试使用 Nothing 作为第二类参数,但它似乎不起作用 (我收到 required: class or interface without bounds 错误 完整错误消息:

RemoteSellerDataSource.java:6: error: unexpected type
public final class RemoteSellerDataSource implements com.bigchangedev.stamps.business.sdk.data.base.data.BaseDataRemote<SellerEntity, ?> {
                                                                                                                       ^
  required: class or interface without bounds
  found:?

谢谢。

编辑:原始答案是纯 Kotlin 答案,因为 OP 没有提到 Dagger。

使用 Nothing 是正确的并且在纯 Kotlin 中工作。但是,Dagger 似乎将您的代码转换为 Java,并且在这样做时它对泛型使用通配符(它不喜欢它,因为它需要精确的类型匹配)。为避免此问题,您可以尝试在通用类型参数上使用 @JvmSuppressWildcards

class RemoteSellerDataSource @Inject constructor(
    private val sellerApi: SellerApi,
    @Named("LANG") private val lang: String
) : BaseDataRemote<SellerEntity, @JvmSuppressWildcards Nothing> {
    override fun getData(params: Nothing?): Single<SellerEntity> {
        return sellerApi.getSeller(lang).map { it.fromApiEntity() }
    }
}

尽管我不确定在 Java 和 Nothing 中会发生什么情况。我想这对 Java 代码的影响应该与删除接口声明中第二个类型参数的 in 方差相同,但不会削弱你的 Kotlin 类型。

另一种解决方法是使用 Unit 而不是 Nothing,在这种情况下,Dagger 很可能会将其转换为 Void。不过,这对您的类型来说不是很好。


原回答:

由于默认值,您在技术上已经可以不带参数地调用 getData()。不关心 params 参数的实现可以一直简单地期望 null。

仅包含 null 而没有其他值的 Kotlin 类型在技术上是 Nothing?,并且由于 getData 是用 Params? 定义的(注意 ?) 作为输入,将 Nothing(即使没有 ?)指定为第二类型参数应该是正确的。所以你应该能够像这样定义一个实现:

interface BaseDataRemote<T, in Params> {
    fun getData(params: Params? = null): Single<T>
}

class ImplementationWithoutParams<T> : BaseDataRemote<T, Nothing> {
    override fun getData(params: Nothing?): Single<T> {
        // params will always be null here
    }
}

为了避免用户混淆,此实现可能会另外提供一个 getData() 完全没有参数的方法:

class ImplementationWithoutParams<T> : BaseDataRemote<T, Nothing> {
    override fun getData(params: Nothing?): Single<T> = getData()

    fun getData(): Single<T> {
        TODO("implementation")
    }
}