假设你有一个巨大的嵌套对象,然后你想修改它的一个属性。
myData.x.y.z = 7;
// or...
myData.a.b.add(9);
看起来问题不大,但实际的编码并没有那么简单。
data class Employee(
val name: String
)
data class Company(
val employees: List<Employee>
)
class MyViewModel : ViewModel() {
// Expose screen UI state
private val _uiState = MutableStateFlow(Company(emptyList()))
val uiState: StateFlow<Company> = _uiState.asStateFlow()
// Handle business logic
fun addEmployee(employee: Employee) {
_uiState.update { currentState ->
currentState.copy(
employees = buildList {
addAll(currentState.employees)
add(employee)
}
)
}
}
}
在实际代码中,基于Single source of truth和Unidirectional Data Flow原则,需要使用不可变数据,在Kotlin中通过
val
关键字实现。
这个对象的嵌套层次不是特别深,实现的功能是
add
。如果要更新List
中的一个元素,代码会比较复杂,而且copy
对象嵌套很深也会造成性能问题
所以,我想要一个像下面这样的方法
doSomeThing
。它创建对象的副本,根据需要修改新对象的属性,并返回这个新对象。
fun addEmployee(employee: Employee) {
_uiState.update { currentState ->
doSomeThing {
currentState.employees.add(employee)
}
}
}
下面添加了一些示例。
将
addEmployee()
功能更改为updateEmployee()
功能。
fun updateEmployee(employee: Employee) {
_uiState.update { currentState ->
currentState.copy(
employees = buildList {
val index = currentState.employees.indexOfFirst { it.name == employee.name }
val temp = currentState.employees.toMutableList()
temp[index] = Employee("jack")
temp.toList()
}
)
}
}
嵌套对象
data class A(
val b: B
)
data class B(
val c: C
)
data class C(
val d: D
)
data class D(
val name: String
)
class MyViewModel : ViewModel() {
fun updateEmployee(employee: Employee) {
_uiState.update { currentState ->
currentState.copy(
b = currentState.b.copy(
c = currentState.b.c.copy(
d = currentState.b.c.d.copy(
name = "John"
)
)
)
)
}
}
}
buildList {
addAll(currentState.employees)
add(employee)
}
Kotlin 已经可以在没有显式突变的情况下做到这一点:
currentState.employees + employee
另外,Kotlin 有
List
和MutableList
、Set
和MutableSet
以及其他集合之间的分离map
, flatMap
, reduce
, fold
, drop
, take
等复制一个深度嵌套的对象也会导致性能问题
不多。当您修补一个字段时,副本的其他字段的值仍然指向相同的对象。