有時候您會想要將一個包含了多個字段的對象分解,以初始化幾個單獨的變量。爲了實現這點,您可使用 Kotlin 的解構聲明功能。繼續閱讀本文以瞭解解構的使用、Kotlin 默認提供的類型、如何在您本身的類和您沒法控制但認爲將會從解構中受益的類中實現解構,以及這一切的內部實現。api
解構聲明容許咱們使用如下方式定義本地值或變量:jvm
/* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ fun play() { val (name, breed) = goodDoggo println("Best doggo: $name") }
使用解構能夠很是方便地處理來自函數或集合的數據:函數
/* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ fun getBestDoggoAndOwner(): Pair<Doggo, Owner> { ...} // 數據來自 Pair 時的用法 fun play() { val (doggo, owner) = getBestDoggoAndOwner() } fun play(doggoOwner: Map<Doggo, Owner>) { // 在集合和循環中使用解構 for( (doggo, owner) in doggoOwner){ ... } }
默認狀況下,全部數據類均支持解構。this
對於一個類的字段,您能夠選擇只用其變量的子集:spa
/* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ data class Doggo( val name: String, val breed: String, val rating: Int = 11 ) val (name, breed, rating) = goodDoggo val (name, breed) = goodDoggo //不須要時能夠忽略 rating 字段
解構不容許您選擇使用某個確切的字段;它永遠使用前 x 個字段,這裏的 x 是您所聲明的變量數。這樣作的缺點是很容易形成錯誤,好比下面這段代碼即可能形成意外的結果:code
val (name, rating) = goodDoggo
rating 值事實上會持有 goodDoggo.breed 的值。您將會看到一個警告: "Variable name ‘rating’ matches the name of a different component" (‘rating’ 變量名匹配了名字不一樣的 component) 而且建議您將 rating 重命名爲 breed。因爲這個警告只存在於 IDE 中,並且不是編譯器警告,您很容易就會注意不到它:component
使用錯誤的解構變量聲明
若是您只須要一部分不連續的字段,可使用 _ 代替那些您不感興趣的字段,Kotlin 將會跳過它們。這樣一來示例就會變成下面這樣:對象
val (name, _, rating) = goodDoggo
讓咱們經過反編譯後的數據類代碼來看看究竟發生了什麼。本文將會只專一於那些爲解構生成的函數,若是須要了解更多關於數據類的信息,請期待咱們將來的文章。索引
想要查看反編譯後的 Java 代碼,您能夠在 Android studio 中使用 Tools -> Kotlin -> Show Kotlin Bytecode 而後點擊 Decompile 按鈕。接口
/* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ public final class Doggo { @NotNull private final String name; @NotNull private final String breed; public Doggo(@NotNull String name, @NotNull String breed, int rating) { ... } ... @NotNull public final String component1() { return this.name; } @NotNull public final String component2() { return this.breed; } ... }
咱們看到編譯器爲主構造函數中聲明的每一個屬性都生成了一個名爲 componentN 的函數,這裏的 N 是字段在主構造函數中的索引。
正如咱們前面所看到的,解構的實現有賴於 componentN 函數。因此若是您想要爲一個不支持解構的類添加解構功能,只須要實現對應的 componentN operator 函數便可。請確保您的函數使用了 operator 前綴。
/* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ class Doggo( val name: String, val breed: String ) { operator fun component1(): String = name operator fun component2(): String = breed ... }
Kotlin 容許您經過擴展函數爲不屬於您的類實現解構。舉個例子,Map.Entry 是一個接口而且不支持解構。爲了方便使用,Kotlin 爲其建立了 component1() 和 component2() 函數,分別返回 Map.Entry 的鍵和值。
當您須要將一個對象的字段拆解爲值或者變量時,可使用解構功能。它在內部是經過提供一系列的 componentN operator 函數實現的,因此當您認爲能夠經過此功能受益時,能夠本身爲您的類提供這些函數,即可以實現解構功能。