(Kotlin/코틀린) data class copy 완전 정리 - 불변 객체, 얕은 복사, 실무 패턴까지

개요


1. copy()란 무엇인가?

copy()는 기존 객체를 기반으로 새로운 객체를 생성하는 함수입니다.

val newUser = oldUser.copy(age = 30)

// 런타임 시
fun copy(name: String = this.name, age: Int = this.age): User {
    return User(name, age)
}

2. copy()는 얕은 복사 (Shallow Copy)

data class Profile(
    val name: String,
    val hobbies: MutableList<String>
)

val p1 = Profile("Kim", mutableListOf("Game"))
val p2 = p1.copy()

// 같은 리스트 참조
p1.hobbies === p2.hobbies  // true

// 문제 상황 (원본도 같이 변경 됨)
p2.hobbies.add("Music")
println(p1.hobbies) // [Game, Music]

3. 깊은 복사가 필요한 경우

val p2 = p1.copy(
    hobbies = p1.hobbies.toMutableList()
)

val p2 = Profile(
    name = p1.name,
    hobbies = p1.hobbies.toMutableList()
)

4. 왜 copy()는 immutable과 같이 쓰나?

copy는 불변 객체(immutable) 패턴에서 가장 강력합니다.

val newUser = user.copy(age = 30)

5. ListAdapter / DiffUtil에서 중요한 이유

ListAdapter는 객체 변경 여부를 기준으로 UI를 갱신합니다.

// ❌ 잘못된 방식
user.age = 30
adapter.notifyItemChanged(position)

// ✅ 올바른 방식
val newList = currentList.map {
    if (it.id == user.id) it.copy(age = 30)
    else it
}

adapter.submitList(newList)

6. default parameter 활용

copy는 default parameter 기반이라 매우 유연합니다.

val user = User("Kim", 20)

val u1 = user.copy()
val u2 = user.copy(name = "Lee")
val u3 = user.copy(age = 40)

7. copy()와 성능


8. 실무에서 자주 쓰는 패턴

// 상태 업데이트
_uiState.value = _uiState.value.copy(
    isLoading = true
)

// 선택 상태 변경
val updated = list.map {
    it.copy(isSelected = it.id == selectedId)
}

// 부분 업데이트
val newUser = oldUser.copy(
    name = inputName
)

// reducer 패턴
state = state.copy(
    items = newItems,
    isLoading = false
)


Related Posts