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
Kotlin中的深度合并数据类_Kotlin_Reflection_Data Class - Fatal编程技术网

Kotlin中的深度合并数据类

Kotlin中的深度合并数据类,kotlin,reflection,data-class,Kotlin,Reflection,Data Class,如何对Kotlin中的两个数据类进行递归/深度合并?大概是这样的: import kotlin.reflect.* import kotlin.reflect.full.* data class Address( val street: String? = null, val zip: String? = null ) data class User( val name: String? = null, val age: Int? = null, val address:

如何对Kotlin中的两个数据类进行递归/深度合并?大概是这样的:

import kotlin.reflect.*
import kotlin.reflect.full.*

data class Address(
  val street: String? = null,
  val zip: String? = null
)

data class User(
  val name: String? = null,
  val age: Int? = null,
  val address: Address? = null
)

inline fun <reified T : Any> T.merge(other: T): T {
  val nameToProperty = T::class.declaredMemberProperties.associateBy { it.name }
  val primaryConstructor = T::class.primaryConstructor!!
  val args = primaryConstructor.parameters.associate { parameter ->
    val property = nameToProperty[parameter.name]!!
    val type = property.returnType.classifier as KClass<*>
    if (type.isData) {
      parameter to this.merge(other) //inline function can't be recursive
    } else {
      parameter to (property.get(other) ?: property.get(this))
    }
  }
  return primaryConstructor.callBy(args)
}

val u1 = User(name = "Tiina", address = Address(street = "Hämeenkatu"))
val u2 = User(age = 23, address = Address(zip = "33100"))

u1.merge(u2)
// expected: User(age = 23, name= "Tiina", address = Address(zip = "33100", street = "Hämeenkatu")
导入kotlin.reflect*
导入kotlin.reflect.full*
数据类地址(
val street:字符串?=null,
val-zip:String?=null
)
数据类用户(
val名称:字符串?=null,
val年龄:Int?=null,
val地址:地址?=null
)
内联乐趣T.merge(其他:T):T{
val nameToProperty=T::class.declaredMemberProperties.associateBy{it.name}
val primaryConstructor=T::class.primaryConstructor!!
val args=primaryConstructor.parameters.associate{parameter->
val property=nametroperty[参数.名称]!!
val type=property.returnType.classifier作为KClass
if(类型为isData){
此参数的参数。merge(other)//内联函数不能是递归函数
}否则{
(property.get(其他)的参数:property.get(此))
}
}
返回primaryConstructor.callBy(args)
}
val u1=用户(name=“Tiina”,address=地址(street=“Hämeenkatu”))
val u2=用户(年龄=23,地址=address(zip=“33100”))
u1.合并(u2)
//预期:用户(年龄=23,姓名=Tiina,地址=address(zip=“33100”,street=“Hämeenkatu”)

相关:

发布的代码中有几个问题

  • 不必要的物化和内联
  • 当检测到isData类型而不是将
    上的属性值合并时,调用了this
    other
    ,因此它变成了无休止的递归
  • 由于差异,
    get
    无法在KProperty1上使用
  • 一些非惯用的东西是有效的,但可以做得更好
  • 这是固定版本。对于生产,我会添加一些检查和错误消息,但这应该适用于“快乐路径”,并有望为您提供构建的基础:

    import kotlin.reflect.KClass
    导入kotlin.reflect.KParameter
    导入kotlin.reflect.KProperty1
    导入kotlin.reflect.full.declaredMemberProperties
    导入kotlin.reflect.full.isSubclassOf
    导入kotlin.reflect.full.primaryConstructor
    数据类地址(
    val street:字符串?=null,
    val-zip:String?=null
    )
    数据类用户(
    val名称:字符串?=null,
    val年龄:Int?=null,
    val地址:地址?=空,
    val映射:映射?=null
    )
    fun mergeData(属性:KProperty1,左:T,右:T):有吗{
    val leftValue=property.getter.call(左)
    val rightValue=property.getter.call(右)
    返回rightValue?让我们{
    if((property.returnType.classifier作为KClass).isSubclassOf(Map::class))(leftValue作为?Map)?.plus(它作为Map)
    else leftValue?合并(it)
    }?:rightValue?:leftValue
    }
    fun lastNonNull(属性:KProperty1,左:T,右:T)=
    property.getter.call(右)?:property.getter.call(左)
    乐趣T.合并(其他:T):T{
    val nameToProperty=this::class.declaredMemberProperties.associateBy{it.name}
    val primaryConstructor=this::class.primaryConstructor!!
    val args:Map=primaryConstructor.parameters.associateWith{parameter->
    val property=nametroperty[参数.名称]!!
    val type=property.returnType.classifier作为KClass
    什么时候{
    type.isData | | type.isSubclassOf(Map::class)->合并数据(属性、此、其他)
    else->lastNonNull(属性、此、其他)
    }
    }
    返回primaryConstructor.callBy(args)
    }
    //核实
    val u1=用户(name=“Tiina”,address=地址(street=“Hämeenkatu”),map=mapOf(“a”到1))
    val u2=用户(年龄=23岁,地址=address(zip=“33100”),地图=mapOf(“b”到2))
    检查(
    u1.合并(u2)=用户(
    年龄=23岁,
    name=“Tiina”,
    地址=地址(zip=“33100”,street=“Hämeenkatu”),
    map=mapOf(“a”到1,“b”到2)
    )
    ) {
    “不起作用”
    }
    println(“工作!”)
    
    首先,你说的深度合并是什么意思?如果u1和u2都定义了一个名称,你预计会发生什么?它应该取u1或u2的名称吗?其次,你真的需要进行一次通用的“深度合并”(即适用于所有数据类型的深度合并)吗?如果你真的问自己“我现在需要这个超级通用的解决方案吗?”答案很可能是否定的。如果你真的需要一个通用的解决方案来深度合并2个对象,那么看起来你走的是一条比较合理的路线。如果两者都定义了一个字段,那么最后一个非空值将获胜。嵌套的数据类应该递归合并。在我的例子中,数据类层次结构很深,所以不需要要手动完成这项工作,需要一个通用的解决方案。来自Clojure,这里有一个动态深度合并:太棒了,谢谢!简单多了,很有效。一条注释:
    mergeValues
    中的最后一行可能是:``返回rightValue?.let{r->leftValue?.let{l->r.merge(l))}?:r}?:leftValue```因此我们在这里也使用非空值。如果你认为这是正确的,你能为未来的求职者更新这个例子吗?是的,我错过了那个案例。更新了代码,尽管与建议的代码略有不同,以提高可读性。建议避免嵌套作用域函数过多。提高可读性,减少重构过程中出错的概率。我很高兴能帮上忙:)很好的解决方案。虽然我希望这能对地图起作用,但事实并非如此
    数据类用户(val name:String?=null,val items:Map?=null)
    用户(items=mapOf(“monitor”到1))
    用户(name=“George”,items=mapOf(“laptop”到2))
    @emanuelgeorgeoategan支持的映射在这里是一个微不足道的补充,我也更新了答案来展示这一点。