iT邦幫忙

2023 iThome 鐵人賽

DAY 6
1

在前面幾天講到了 Kotlin immutable 3劍客,今天要來講最後一個 Data class 的 copy.

先複習一下 immutable 三劍客

  1. 唯讀屬性 val properties
  2. 不可變的 collections
  3. data classes 的 copy

這邊說的不可變的 data class 指的是把屬性都宣告成 val,如以下程式碼,這樣 new 出來的 user object 不能直接改動屬性

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

因為不可變的 object 在內部狀態上不會發生變化,就像 String 或 Int 一樣。除了前面提到的為何我們偏好較少的可變性之外,不可變 object 還有它們自己的優點:

  • 更容易推理,因為它們的狀態在被建立後保持不變
  • 不可變性使得程式的平行化(Parallel)更容易,因為共享 object 之間沒有衝突
  • 容易的被快取(cache),因為它們不會改變

使用不可變對象當作 Map Key 或加入 Set

我們可以使用不可變對象當作 Map 中的 key 或是放心加入 Set 當中。因為我們都知道在 Kotlin/JVM 下,這兩種集合都使用 hash table 比較是否重覆
反之,本書極度的不建議以可變的 object 當作 Map Key。因為當我們修改已經在 hash table 中分類的元素時,其 hash 可能不再正確,因此我們可能找不到它

以下程式碼說明了這樣的危險性

val names: SortedSet<FullName> = TreeSet()
val person = FullName("AAA", "AAA")
names.add(person)
names.add(FullName("Jordan", "Hansen"))
names.add(FullName("David", "Blanc"))

print(s) // [AAA AAA, David Blanc, Jordan Hansen]
print(person in names) // true

person.name = "ZZZ"
print(names) // [ZZZ AAA, David Blanc, Jordan Hansen]
print(person in names) // false

如以上程式碼,可變對象更加危險且不可預測

不可變性與 data class copy

但我們的程式還是要進行 state 的轉變,所以這些不可變對象應該具有所需更改的此對象副本的方法。例如,Int 是不可變的,並且它有許多方法,如 plus 或 minus,這些方法不會修改它,而是返回操作結果的新 Int。同樣的方法可以應用到我們的不可變對象上。例如,假設我們有一個不可變的 User 類,我們需要允許其姓氏更改。我們可以提供withSurname 方法來支持它,該方法產生一個具有特定屬性更改的副本

class User(
    val name: String,
    val surname: String,
) {
    fun withSurname(surname: String) = User(name, surname)
}

編寫此類函數當然是可能的,但如果需要為每一個屬性都寫一個,那會非常繁瑣。此時,資料修飾器(data modifier)便派上用場。它生成的方法之一就是 copy。copy 方法會創建一個新的實例,其中所有屬性默認都與前一個實例相同。同時,也可以指定新的值

data class User(
    val name: String,
    val surname: String,
)

var user = User("Brandy", "Lin")
user = user.copy(surname = "Chang")
print(user) // User(name=Brandy, surname=Chang)

簡潔而靈活的 copy

所以在 Kotlin 中,使用 data class 的 copy 方法對於不可變是十分有善的。使用 copy 方法可以非常容易地生成新的修改過的實例,而原始對象保持不變。此外,copy 也具有以下好處:

  • 簡潔性:不需要手動寫拷貝方法,data class 會自動為我們生成 copy 方法
  • 靈活性:使用 copy 方法時,您可以選擇哪些屬性保持不變,哪些屬性需要更新
  • 避免錯誤:由於 copy 方法是自動生成的,因此減少了手動 copy 時可能出現的錯誤
  • 效率:由於 copy 方法是自動生成的,它通常會為特定的 data class 進行優化,從而提供更好的性能

每日一推 (G)I-DLE

今天來介紹少見的慢版 ESCAPE。但很耐聽,也有人說這首是寫給前團員

Yes


上一篇
D05: listOf, mapOf 就是要讓你儘量使用不可變的集合 - Immutable Collection in Kotlin
下一篇
D07: 料敵從寬, 在邊界就處理外界來的 nullable
系列文
讓 Kotlin 程式碼更道地 - 談 Effective Kotlin 與相關的 Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言