Generics 从泛型函数返回特定实例
我的问题是关于泛型方法的类型推断 我有以下场景:Generics 从泛型函数返回特定实例,generics,kotlin,Generics,Kotlin,我的问题是关于泛型方法的类型推断 我有以下场景: 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(ty
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)
}
接口对象{
valid:String
}
数据类用户(覆盖val Id:String,val名称:String):Obj
数据类案例(覆盖val Id:String,val主题:String):Obj
接口Api{
fun getLastUpdated(类型:KClass,backTill:Duration=Duration.of Days(1)):LastUpdated
fun getDetails(类型:KClass,uuid:String):详细信息
数据类LastUpdatedResponse(val id:List=emptyList(),
val latestDateCovered:String=“”)
数据类LastUpdated(val错误:Throwable?=null,val响应:LastUpdatedResponse?=null)
数据类详细信息响应(val:T)
数据类详细信息(val错误:Throwable?=null,val响应:DetailsResponse?=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())
}
}
}
val testCase=Case(“123”,“测试”)
val testUser=User(“321”,“虚拟”)
val mockApi=对象:Api{
覆盖有趣的getLastUpdated(类型:KClass,返回时间:Duration):Api.LastUpdated{
返回Api.LastUpdated(response=Api.LastUpdatedResponse(listOf(“123”))
}
覆盖有趣的getDetails(类型:KClass,uuid:String):详细信息{
何时(输入){
Case::class->return Api.Details(response=Api.DetailsResponse(wrapped=testCase))//return Api.Details(response=Api.DetailsResponse(wrapped=testUser))//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
错误:(114,43)Kotlin:类型推断失败。预期类型不匹配:推断类型为Api.Details,但预期为Api.Details
我可以让它与铸造一起工作:
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>
when(类型){
Case::class->返回Api.Details(response=Api.DetailsResponse(wrapped=testCase))作为Api.Details
User::class->返回Api.Details(response=Api.DetailsResponse(wrapped=testUser))作为Api.Details
但随后我收到一条警告,通知我“此强制转换将永远不会成功”——运行我的测试,它会按预期运行
我的问题是-为什么在没有强制转换的情况下不能工作?我应该使用什么来代替?方差注释可能会帮助您,只需在以下函数(在接口和实现器类中)中将通用参数t更改为out Obj:
fun getDetails(类型:KClass,uuid:String):详细信息
这应该可以解决您的问题:
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())
}
}
override-fun-getDetails(类型:KClass,uuid:String):Api.Details{
何时(输入){
Case::class->返回Api.Details(response=Api.DetailsResponse(wrapped=testCase))
User::class->返回Api.Details(response=Api.DetailsResponse(wrapped=testUser))
else->return Api.Details(错误=UnsupportedOperationException())
}
}
为了更好地理解它,您可以阅读kotlin关于泛型差异的文档:
有些事情在java中是无法做到的:
Collection<String> strings = ...
Collection<Object> objs = strings; // this will fail
集合字符串=。。。
集合objs=strings;//这将失败
在很多情况下,您只想读取泛型对象,因此进行赋值没有问题。告诉kotlin这是可能的方法是使用in和out。in表示您要读取泛型,但不写入泛型,out表示您要写入泛型。在哪一行出现异常?请在上面画一个记号comment@voddan完全忘记了这在“使用强制转换”行中并不明显。有标记,不幸的是行很长。为什么要使用kClass?我认为如果要使用类/接口的扩展,使用该类不是一个好主意。为什么不这样:
kotlin fun getDetails(obj:obj,uuid:String):Details{when(obj){is User->->->return Api.Details(response=Api.DetailsResponse(wrapped=obj))是Case->……}
@jorgemf:完整签名是fun getDetails(type:KClass,uuid:String,fields:List=type.members.map{it.name})
,除此之外,我只使用type
向jackson发送反序列化目标的信号。@mabi基于@x2bool解决方案和对话。我认为您想要做的是不可能的,您无法定义一个函数,该函数有时会返回详细信息和其他详细信息,它将始终返回详细信息。因此,您需要强制转换。您可以做的一件事是将函数的输出值添加为输入元素。fun getDetails(type:kClass,uuid:String,…,output:Details)
然后使用所需的具体细节类调用函数,并且只在细节中添加对象:getDetails(Case::kClass,Api.Details())
这当然让我摆脱了强制转换,非常好!但现在我将每个返回值都减少到Obj
即,我将无法访问带有强制转换的Case.subject。那么你就不能这样做。你正试图从泛型函数返回两个特定类型。你必须指定下限。
Collection<String> strings = ...
Collection<Object> objs = strings; // this will fail