我的问题是关于使用泛型方法的类型推断。
我有以下情况:
interface Obj {
val Id: String
}
data class User(override val Id: String, val name: String): Obj
data class Case(override val Id: String, val subject: String): Obj
interface Api {
fun <T: Obj> getLastUpdated(type: KClass<T>, backTill: Duration = Duration.ofDays(1)): LastUpdated
fun <T: Obj> getDetails(type: KClass<T>, uuid: String): Details<T>
data class LastUpdatedResponse(val ids: List<String> = emptyList(),
val latestDateCovered: String = "")
data class LastUpdated(val error: Throwable? = null, val response: LastUpdatedResponse? = null)
data class DetailsResponse<T>(val wrapped: T)
data class Details<T>(val error: Throwable? = null, val response: DetailsResponse<T>? = null)
}
在我的测试中,我需要确切地知道模拟的API需要返回什么,因此
val testCase = Case("123", "Testing")
val testUser = User("321", "Dummy")
val mockApi = object: Api {
override fun <T : Obj> getLastUpdated(type: KClass<T>, backTill: Duration): Api.LastUpdated {
return Api.LastUpdated(response = Api.LastUpdatedResponse(listOf("123")))
}
override fun <T : Obj> getDetails(type: KClass<T>, uuid: String): Details<T> {
when (type) {
Case::class -> return Api.Details(response = Api.DetailsResponse(wrapped = testCase)) // <- this fails
User::class -> return Api.Details(response = Api.DetailsResponse(wrapped = testUser)) // <- as does this
else -> return Api.Details(error = UnsupportedOperationException())
}
}
}
然而,这无法编译:
Error:(114, 43) Kotlin: Type inference failed. Expected type mismatch: inferred type is Api.Details<Case> but Api.Details<T> was expected
我可以使用cast进行操作:
when (type) {
Case::class -> return Api.Details(response = Api.DetailsResponse(wrapped = testCase)) as Api.Details<T>
User::class -> return Api.Details(response = Api.DetailsResponse(wrapped = testUser)) as Api.Details<T>
然后我收到一条警告告诉我&#34;这个演员将永远不会成功&#34; - 运行我的测试,它确实按预期工作。
我的问题是 - 为什么没有强制转换这项工作,我应该使用什么呢?
答案 0 :(得分:1)
方差注释可能对您有所帮助,只需在以下函数中更改泛型参数 T 为 out Obj (在接口和实现者类中):
fun <T: Obj> getDetails(type: KClass<T>, uuid: String): Details<out Obj>
答案 1 :(得分:1)
这可以解决您的问题:
override fun getDetails(type: KClass<in Obj>, uuid: String): Api.Details<out Obj> {
when (type) {
Case::class -> return Api.Details(response = Api.DetailsResponse(wrapped = testCase))
User::class -> return Api.Details(response = Api.DetailsResponse(wrapped = testUser))
else -> return Api.Details(error = UnsupportedOperationException())
}
}
为了更好地理解它,您可以阅读关于泛型中方差的kotlin文档:https://kotlinlang.org/docs/reference/generics.html
在java中你不能做的事情是:
Collection<String> strings = ...
Collection<Object> objs = strings; // this will fail
在很多情况下,您只想阅读泛型对象,以便进行该分配没有问题。告诉kotlin这是可能的方法是使用输入和输出的单词。在意味着你将阅读泛型而不是写出它们并且意味着你要写它们。