从泛型函数返回特定的实例
我的问题是关于泛型方法的类型推断。
我有以下情况:
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这个可能的方法是使用单词进出。 这意味着你要阅读泛型,但不写出来,意味着你要写他们。