gpt4 book ai didi

kotlin - Kotlin 中的深度合并数据类

转载 作者:行者123 更新时间:2023-12-02 12:37:58 24 4
gpt4 key购买 nike

如何在 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")

相关: Combining/merging data classes in Kotlin

最佳答案

贴出的代码有几个问题,

  • 不必要的具体化和内联
  • 当检测到类型 isData 而不是在 this 上合并属性的值时与 other被调用,所以变成了无限递归。
  • get由于方差
  • 不能用于 KProperty1
  • 一些有效但可以做得更好的非惯用语

  • 这是固定版本。对于生产,我会添加一些检查和错误消息,但这应该适用于“快乐路径”,并希望为您提供基础:
    import kotlin.reflect.KClass
    import kotlin.reflect.KParameter
    import kotlin.reflect.KProperty1
    import kotlin.reflect.full.declaredMemberProperties
    import kotlin.reflect.full.isSubclassOf
    import kotlin.reflect.full.primaryConstructor

    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,
    val map: Map<String, Int>? = null
    )

    fun <T> mergeData(property: KProperty1<out T, Any?>, left: T, right: T): Any? {
    val leftValue = property.getter.call(left)
    val rightValue = property.getter.call(right)
    return rightValue?.let {
    if ((property.returnType.classifier as KClass<*>).isSubclassOf(Map::class)) (leftValue as? Map<*, *>)?.plus(it as Map<*, *>)
    else leftValue?.merge(it)
    } ?: rightValue ?: leftValue
    }

    fun <T> lastNonNull(property: KProperty1<out T, Any?>, left: T, right: T) =
    property.getter.call(right) ?: property.getter.call(left)

    fun <T : Any> T.merge(other: T): T {
    val nameToProperty = this::class.declaredMemberProperties.associateBy { it.name }
    val primaryConstructor = this::class.primaryConstructor!!
    val args: Map<KParameter, Any?> = primaryConstructor.parameters.associateWith { parameter ->
    val property = nameToProperty[parameter.name]!!
    val type = property.returnType.classifier as KClass<*>
    when {
    type.isData || type.isSubclassOf(Map::class) -> mergeData(property, this, other)
    else -> lastNonNull(property, this, other)
    }
    }
    return primaryConstructor.callBy(args)
    }


    // verification

    val u1 = User(name = "Tiina", address = Address(street = "Hämeenkatu"), map = mapOf("a" to 1))
    val u2 = User(age = 23, address = Address(zip = "33100"), map = mapOf("b" to 2))

    check(
    u1.merge(u2) == User(
    age = 23,
    name = "Tiina",
    address = Address(zip = "33100", street = "Hämeenkatu"),
    map = mapOf("a" to 1,"b" to 2)
    )
    ) {
    "doesn't work"
    }

    println("Works!")

    关于kotlin - Kotlin 中的深度合并数据类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59950612/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com