Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 从泛型函数返回特定实例_Generics_Kotlin - Fatal编程技术网

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