使用不可变属性更改Kotlin中对象的状态

时间:2018-06-19 07:57:03

标签: kotlin

在Kotlin,我们有这种不可变属性的概念。

我曾经听说过在功能编程中,状态不应该改变。我一直在域模型的背景下思考这个问题。

假设我们有一个Person课程(请不要介意这个非常愚蠢和不切实际的例子)。

class Person(val firstName: String, val lastName: String, val age: Int)

Everything属性是不可变的,这很好。

现在有人出现并要求更换名字。所以我创建了一个可以做到这一点的函数。

fun replaceFirstName(person: Person, newFirstName: String): Person {
    return Person(newFirstName, person.lastName, person.age)
}

现在这看起来真的很难看我的眼睛。在这种情况下,只有3个属性,其中一个应该被替换。但你可以想象在较大的域类中它会是什么样子。

简单的做法就是将val替换为var,但随后不变的整个意图就消失了。

我正在寻找类似的东西(由于没有复制功能,它会抛出错误):

fun replaceName(person: Person, newFirstName: String): Person {
    return person.copy { firstName = newFirstName }
}

在Kotlin有一个简洁明了的方法吗?

2 个答案:

答案 0 :(得分:3)

Kotlin的概念为Data classes,具有您需要的copy功能。因此,如果您将您的课程声明为:

data class Person(val firstName:String, val lastName:String, val age:Int)

您将能够使用此功能。此外,它还会为您生成equals()/hashCode/toString()

答案 1 :(得分:3)

如果您有兴趣,也可以使用lens执行此操作。

这可能不是一个简单的案例,但是当你有非常深的对象只需要改变一个属性时,它就会很有用:

import arrow.optics.*

data class Person(val firstName:String, val lastName:String, val age:Int)

val firstNameLens: Lens<Person, String> = Lens(
    get = { person -> person.firstName },
    set = { newFirstName-> { person -> person.copy(firstName = newFirstName) } }
)

然后你可以这样做:

val doe = Person("John", "Doe", 30)
firstNameLens.set(doe, "Henry")
//output: Person(firstName = "Henry", lastName = "Doe", age = 30)

val doe = Person("John", "Doe", 30)
firstNameLens.get(doe)
//output: "John"

val doe = Person("John", "Doe", 30)
firstNameLens.modify(doe, { it + "ny" })
//output: Person(firstName = "Johnny", lastName = "Doe", age = 30)