I would like to return a copy of a class with a different value assigned to a val
property.
data class Person(val name: String, val age: Int)
fun main() {
val person = Person("Morné", 25)
val property = person::class.declaredMemberProperties.first { it.name == "age" }
person.copyWithValue(property.name, 22)
}
if age
was a var
then I could do it like follows:
fun main() {
val person = Person("Morné", 25)
val property = person::class.declaredMemberProperties.first { it.name == "age" }
if (property is KMutableProperty<*>)
property.setter.call(person, 22)
}
If you really want to return just a copy of the object, you can use copy
, e.g.:
fun main() {
val person = Person("Morné", 25)
val newPerson = person.copy(age = 22)
}
Otherwise if you really must edit the age
it must not be a val
in the first place. Using reflection you could still adapt the value, but if the answers up to here already suffice, they are the way to go...
For a more dynamic way you can use the following (I would still target the copy
-method, as then you wouldn't accidently update the current object):
val person = Person("Morné", 25)
val updates = mapOf("lastname" to "N/A", "age" to 22)
val copiedPerson = with(person::class.memberFunctions.first { it.name == "copy" }) {
callBy(mapOf(instanceParameter!! to person)
.plus(updates.mapNotNull { (property, newValue) ->
parameters.firstOrNull { it.name == property }
?.let { it to newValue }
})
)
}
println(copiedPerson)
which prints:
Person(name=Morné, age=22)
You could also use something like .let { person::class.cast(it }
after callBy
if you want to continue with the actual type. If you only want this to work with the Person
type you could also exchange person
with Person
and cast it directly to as Person
.