Kotlin:比较不同目标对象的属性值和(外)反射

我想比较数据类的多个实例之间的值,以便我知道哪个值更改:

data class A(val name : String) val firstA = A("hello") val secondA = A("you") if (secondA.name.changed(firstA)) { // Do something } 

我可以以某种方式访问.name的属性函数,并在没有明确定义的情况下在另一个目标值(在本例中为firstA)上执行它? 可以在这里委托帮助,或者如何解决这个问题,而不是反思?

使用反射

使用Kotlin反射库,您可以使用memberProperties并通过不同的值进行过滤

 import java.util.* import kotlin.reflect.full.memberProperties data class Example(val a: Int, val b:Long, val c: String) fun main(args: Array<String>) { val start = Example(1,2, "A") val end = Example(1,4, "B") val differentFields = Example::class.memberProperties.filter { val startValue = it.get(start) val endValue = it.get(end) !Objects.equals(startValue, endValue) } differentFields.forEach { println(it.name) } } 

产量

 b c 

不使用反射

您需要明确地检查每个方法(或将它们存储在列表中并遍历它们)

没有列表

 import java.util.* data class Example(val a: Int, val b:Long, val c: String) { fun getChanged(other: Example): List<String> { val ret: MutableList<String> = mutableListOf() if (!Objects.equals(a, other.a)) ret.add("a") if (!Objects.equals(b, other.b)) ret.add("b") if (!Objects.equals(c, other.c)) ret.add("c") return ret } } fun main(args: Array<String>) { val start = Example(1,2, "A") val end = Example(1,4, "B") println(start.getChanged(end)) } 

与列表

 import java.util.* data class Example(val a: Int, val b:Long, val c: String) { data class Field(val function: (Example) -> Any?, val name: String) val fields: List<Field> = listOf( Field({ it.a }, "a"), Field({ it.b }, "b"), Field({ it.c }, "c") ) fun getChanged(other: Example): List<String> { return fields.filter { !Objects.equals(it.function(this), it.function(other)) }.map { it.name } } } fun main(args: Array<String>) { val start = Example(1,2, "A") val end = Example(1,4, "B") println(start.getChanged(end)) } 

没有反思

我找到了一种不使用反射的方法:

 interface DiffValue<T> { val old : T? } fun <T,R> T.changed(memberAccess : T.() -> R) : Boolean { if (this is DiffValue<*>) { val old = this.old as? T if (old != null) { val currentValue = with(this, memberAccess) val previousValue = with(old, memberAccess) return currentValue != previousValue } } return true } 

这就是你如何使用它:

 data class A(val val name: String, override val old : A? = null) val firstA = A("hello") val secondA = A("you", firstA) if (secondA.changed {name}) { // Do something } 

这是基于带有接收器的lambda文字的概念,允许Kotlin构建强大的构建器和DSL。

注意: DiffValue接口是可选的,只是用来使值更容易保持在一起,并避免了changed的附加参数。