我想比较数据类的多个实例之间的值,以便我知道哪个值发生了变化:
data class A(val name : String)
val firstA = A("hello")
val secondA = A("you")
if (secondA.name.changed(firstA)) {
// Do something
}
我可以以某种方式访问
.name
的属性函数并在另一个目标值上执行它(在本例中是在firstA 上)而不显式定义它吗?
代表们可以在这里提供帮助吗?或者我如何通过反思或不反思来解决这个问题?
我找到了一种不使用反射的方法:
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 name: String, override val old : A? = null): DiffValue<A>
val firstA = A("hello")
val secondA = A("you", firstA)
if (secondA.changed {name}) {
// Do something
}
这是基于 带有接收器的 lambda 文字的概念,它允许 Kotlin 构建强大的构建器和 DSL。
注意:
DiffValue
接口是可选的,只是用于更容易地将值保存在一起,并避免在 changed
中添加额外参数。
使用 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))
}