从泛型函数返回特定的实例

我的问题是关于泛型方法的类型推断。

我有以下情况:

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 

我可以使它与铸造一起工作:

 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> 

但后来我收到一个警告,告诉我“这个演员永远不会成功” – 运行我的测试,它的确如预期的那样工作。

我的问题是 – 为什么这不工作,而不是铸造,我应该使用什么?

方差注释可能对你有所帮助,只需在下面的函数中(在接口和实现者类中)将泛型参数T改为Obj即可

 fun <T: Obj> getDetails(type: KClass<T>, uuid: String): Details<out Obj> 

这应该可以解决你的问题:

  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这个可能的方法是使用单词进出。 这意味着你要阅读泛型,但不写出来,意味着你要写他们。