如何合并Kotlin中含可空对象列表的数据类实例
问题:合并包含可空列表的数据类实例
我在Kotlin中定义了如下包含可空对象列表的数据类:
data class exampleClass( var list1: List<SomeObject1>?, var list2: List<SomeObject2>?, var list3: List<SomeObject3>? ) data class SomeObject1( var id: String, var info: String, ) data class SomeObject2( var id: String, var info: String, ) data class SomeObject3( var id: String, var info: String, )
现有一组exampleClass对象列表,希望将它们合并为一个exampleClass实例,其中各对应列表需进行合并(若两个实例的对应列表均非空)。例如三个exampleClass实例合并后,list1需包含所有实例中list1的元素,list2、list3同理。
我尝试了如下merge扩展函数:
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.associateWith { parameter -> val property = nameToProperty[parameter.name]!! (property.get(other) ?: property.get(this)) } return primaryConstructor.callBy(args) }
但该函数仅在其中一个列表为null时生效,若两个列表均非空会直接替换而非合并,导致list1的原有元素被后续实例的list1覆盖。请问如何实现正确的合并逻辑?
解决方案
你需要修改扩展函数,针对可空List类型的属性做特殊合并逻辑:当两个实例的对应列表都非空时,拼接它们的元素;如果其中一个为null,取非空的那个;都为null则保持null。非List类型的属性可以保留原逻辑(优先取另一个实例的值,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.associateWith { parameter -> val property = nameToProperty[parameter.name]!! val thisValue = property.get(this) val otherValue = property.get(other) // 处理可空List的合并 if (property.returnType.isSubtypeOf(List::class.starProjectedType)) { when { thisValue == null && otherValue == null -> null thisValue == null -> otherValue otherValue == null -> thisValue else -> (thisValue as List<*>) + (otherValue as List<*>) } } else { // 非List类型:优先用other的值,null则用当前实例的 otherValue ?: thisValue } } return primaryConstructor.callBy(args) }
合并列表的使用示例
用fold函数遍历累积合并结果:
// 示例数据 val exampleList = listOf( exampleClass(listOf(SomeObject1("1", "info1")), null, null), exampleClass(null, listOf(SomeObject2("2", "info2")), null), exampleClass(listOf(SomeObject1("3", "info3")), listOf(SomeObject2("4", "info4")), listOf(SomeObject3("5", "info5"))) ) // 合并所有实例 val mergedResult = exampleList.fold(exampleClass(null, null, null)) { acc, item -> acc.merge(item) }
补充说明
- 函数通过Kotlin反射识别List类型属性,确保只有列表会执行合并逻辑,其他类型保持原有替换规则。
- 如果你的数据类中有其他需要自定义合并逻辑的类型,可以在函数中新增对应的判断分支。
- 建议遵循Kotlin命名规范,将类名改为大驼峰形式(比如
ExampleClass),提升代码可读性。
内容的提问来源于stack exchange,提问作者aryakdangol
相关产品推荐
相关产品推荐

