如何在修改后得到一个新的不可变对象?

问题描述 投票:0回答:1

假设你有一个巨大的嵌套对象,然后你想修改它的一个属性。

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 truthUnidirectional 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"
            )
          )
        )
      )
    }
  }
}
android kotlin immutability
1个回答
0
投票
buildList {
    addAll(currentState.employees)
    add(employee)
}

Kotlin 已经可以在没有显式突变的情况下做到这一点:

currentState.employees + employee

另外,Kotlin 有

  • List
    MutableList
    Set
    MutableSet
    以及其他集合之间的分离
  • map
    ,
    flatMap
    ,
    reduce
    ,
    fold
    ,
    drop
    ,
    take
  • 的批量操作
  • 无需创建大量副本即可执行多个批量操作的序列

复制一个深度嵌套的对象也会导致性能问题

不多。当您修补一个字段时,副本的其他字段的值仍然指向相同的对象。

© www.soinside.com 2019 - 2024. All rights reserved.