我可以省略泛型中的类型吗? - 科特林
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")
}
}
如果我有如下界面:
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")
}
}