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