Kotlin 解構宣告 (Destructuring Declarations)

在 Kotlin 中,解構宣告 (Destructuring Declarations) 是一個非常實用語法特性,它允許你將一個物件「拆解」成多個獨立的變數。這能讓程式碼變得更簡潔、更易讀。

簡單來說,解構宣告讓你可以用一行程式碼完成多個變數的賦值。

基本語法

解構宣告的語法如下:

val (name, age) = person

這行程式碼會同時建立兩個新變數 name 和 age。

順序很重要:解構是基於位置而非變數名稱。如果你在 data class 中調換了屬性的定義順序,解構時賦值的內容也會跟著改變。

變數數量限制:雖然沒有嚴格限制,但解構過多變數(例如超過 5 個)會讓程式碼難以維護,建議適度使用。

常見的使用場景

資料類別 (Data Classes)

這是解構宣告最常發揮的地方。Kotlin 會自動為 data class 生成對應的 componentN() 函數。

data class User(val name: String, val age: Int)

fun main() {
    val user = User("Alice", 25)
    
    // 解構宣告
    val (name, age) = user
    
    println("姓名:$name, 年齡:$age")
}

遍歷 Map

在處理 Map 集合時,解構宣告非常方便,可以直接提取 Key 和 Value。

val map = mapOf("Apple" to 10, "Banana" to 20)

for ((key, value) in map) {
    println("$key 的價格是 $value 元")
}

函數回傳多個值

雖然函數通常只能回傳一個物件,但透過 Pair 或 Triple 配合解構,可以達到回傳多個值的效果。

fun getResult(): Pair<String, Int> {
    return Pair("Success", 200)
}

val (status, code) = getResult()

使用底線 _ 跳過不需要的變數

如果你只需要解構物件中的某幾個屬性,可以使用底線來忽略其餘部分,避免編譯器發出「未使用變數」的警告。

val (_, age) = user // 只取 age,忽略第一個屬性 name

在 Lambda 表達式中使用

解構也可以直接用在 Lambda 的參數列中:

val list = listOf(User("Bob", 30))
list.map { (name, age) -> "$name is $age years old" }

底層原理:componentN() 函數

為什麼解構宣告可以運作?其實 Kotlin 在幕後將解構編譯成了對 componentN() 函數的呼叫:

// 你寫的:
val (name, age) = user

// 編譯器實際執行的:
val name = user.component1()
val age = user.component2()

如果你想讓自定義的普通類別(非 data class)也支援解構,你需要手動實作 operator fun componentN():

class CustomPoint(val x: Int, val y: Int) {
    operator fun component1() = x
    operator fun component2() = y
}
當你寫下 val (x, y) = point 時,編譯器並不知道該如何拆解這個物件。它會去尋找名為 component1()component2() 的函數。但為了確保開發者不是「不小心」命名了這些函數,而是「刻意」要支援解構語法,Kotlin 要求必須加上 operator 修飾符。