You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中使用泛型扩展函数实现两类data class的映射

错误原因

你写的泛型方法报错是因为Kotlin泛型存在运行时类型擦除,无法直接通过T实例化目标类对象,且不同模型类的字段映射规则存在差异,无法实现无规则的自动通用转换。

推荐实现方案

方案1:无反射类型安全实现(优先推荐)

通过传入映射函数的方式实现,性能更高、逻辑可控,不会有类型安全问题。

// 泛型扩展函数定义
fun <Source, Target> Source.graphqlToDomain(mapper: (Source) -> Target): Target = mapper(this)

使用示例:

// 单对象转换
val graphClient: HomeRequestBodyWithAuthQuery.Client = // 接口返回的GraphQL模型
val domainClient = graphClient.graphqlToDomain { 
    Client(id = it.id, givenName = it.givenName) 
}

// 字段完全匹配时可以直接传入构造函数引用
val domainClient = graphClient.graphqlToDomain(::Client)

// 列表转换也可以直接复用
val domainClientList = graphClientList.map { it.graphqlToDomain(::Client) }

方案2:自动映射反射实现

如果你的模型类字段名和类型完全匹配,可以用内联具体化泛型+反射实现无需传参的自动转换,减少重复代码。

  1. 先添加kotlin反射依赖(build.gradle.kts):
dependencies {
    implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.0") // 版本和你项目kotlin版本保持一致
}
  1. 扩展函数实现:
import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.full.memberProperties

inline fun <reified Target> Any.graphqlToDomain(): Target {
    val targetClass = Target::class
    val constructor = targetClass.primaryConstructor
        ?: throw IllegalArgumentException("${targetClass.simpleName}不存在主构造函数")
    
    val sourceFields = this::class.memberProperties.associateBy { it.name }
    val params = constructor.parameters.associateWith { param ->
        sourceFields[param.name]?.get(this)
    }
    return constructor.callBy(params)
}

使用示例:

val domainClient = graphClient.graphqlToDomain<Client>()
val domainClientList = graphClientList.map { it.graphqlToDomain<Client>() }

注意:该方案依赖反射,会有少量性能损耗,字段名或类型不匹配时会抛出运行时异常,适合模型字段匹配度极高的场景使用。

内容的提问来源于stack exchange,提问作者Saeed Noshadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 01:36:00