有時把一個對象 解構(gòu) 成很多變量會很方便,例如:
val (name, age) = person
這種語法稱為 解構(gòu)聲明 。一個解構(gòu)聲明同時創(chuàng)建多個變量。
我們已經(jīng)聲明了兩個新變量:name 和 age,并且可以獨(dú)立使用它們:
println(name)
println(age)
一個解構(gòu)聲明會被編譯成以下代碼:
val name = person.component1()
val age = person.component2()
其中的 component1() 和 component2() 函數(shù)是在 Kotlin 中廣泛使用的 約定原則 的另一個例子。
(參見像 + 和 *、for{: .keyword }-循環(huán)等操作符)。
任何表達(dá)式都可以出現(xiàn)在解構(gòu)聲明的右側(cè),只要可以對它調(diào)用所需數(shù)量的 component 函數(shù)即可。
當(dāng)然,可以有 component3() 和 component4() 等等。
請注意,componentN() 函數(shù)需要用 operator 關(guān)鍵字標(biāo)記,以允許在解構(gòu)聲明中使用它們。
解構(gòu)聲明也可以用在 for{: .keyword }-循環(huán)中:當(dāng)你寫
for ((a, b) in collection) { …… }
變量 a 和 b 的值取自對集合中的元素上調(diào)用 component1() 和 component2() 的返回值。
讓我們假設(shè)我們需要從一個函數(shù)返回兩個東西。例如,一個結(jié)果對象和一個某種狀態(tài)。
在 Kotlin 中一個簡潔的實(shí)現(xiàn)方式是聲明一個數(shù)據(jù)類并返回其實(shí)例:
data class Result(val result: Int, val status: Status)
fun function(……): Result {
// 各種計算
return Result(result, status)
}
// 現(xiàn)在,使用該函數(shù):
val (result, status) = function(……)
因?yàn)閿?shù)據(jù)類自動聲明 componentN() 函數(shù),所以這里可以用解構(gòu)聲明。
注意:我們也可以使用標(biāo)準(zhǔn)類 Pair 并且讓 function() 返回 Pair<Int, Status>,
但是讓數(shù)據(jù)合理命名通常更好。
可能遍歷一個映射(map)最好的方式就是這樣:
for ((key, value) in map) {
// 使用該 key、value 做些事情
}
為使其能用,我們應(yīng)該
iterator() 函數(shù)將映射表示為一個值的序列,component1() 和 component2() 來將每個元素呈現(xiàn)為一對。當(dāng)然事實(shí)上,標(biāo)準(zhǔn)庫提供了這樣的擴(kuò)展:
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
因此你可以在 for{: .keyword }-循環(huán)中對映射(以及數(shù)據(jù)類實(shí)例的集合等)自由使用解構(gòu)聲明。
如果在解構(gòu)聲明中你不需要某個變量,那么可以用下劃線取代其名稱:
val (_, status) = getResult()
你可以對 lambda 表達(dá)式參數(shù)使用解構(gòu)聲明語法。
如果 lambda 表達(dá)式具有 Pair 類型(或者 Map.Entry 或任何其他具有相應(yīng) componentN 函數(shù)的類型)的參數(shù),那么可以通過將它們放在括號中來引入多個新參數(shù)來取代單個新參數(shù):
map.mapValues { entry -> "${entry.value}!" }
map.mapValues { (key, value) -> "$value!" }
注意聲明兩個參數(shù)和聲明一個解構(gòu)對來取代單個參數(shù)之間的區(qū)別:
{ a //-> …… } // 一個參數(shù)
{ a, b //-> …… } // 兩個參數(shù)
{ (a, b) //-> …… } // 一個解構(gòu)對
{ (a, b), c //-> …… } // 一個解構(gòu)對以及其他參數(shù)
如果解構(gòu)的參數(shù)中的一個組件未使用,那么可以將其替換為下劃線,以避免編造其名稱:
map.mapValues { (_, value) -> "$value!" }
你可以指定整個解構(gòu)的參數(shù)的類型或者分別指定特定組件的類型:
map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" }
map.mapValues { (_, value: String) -> "$value!" }