はじめに
Kotlin の便利な構文のひとつに
「分解宣言(Destructuring Declaration)」 があります。
これは、オブジェクトを複数の変数に一度に分解して代入する 機能です。
Java では面倒だった値の取り出しを、Kotlin では直感的に書けます。
基本構文
val (a, b) = Pair(1, 2)
println(a) // 1
println(b) // 2
上記のように Pair などのオブジェクトを
「タプルのように」分解できます。
この構文は componentN() 関数(component1()、component2()...)を内部的に呼び出しています。
動作原理:componentN() 関数
Kotlin の分解宣言は、対象オブジェクトが以下のような componentN() メソッドを持っているときに動作します。
data class User(val name: String, val age: Int)
val user = User("Anna", 28)
val (name, age) = user
println(name) // Anna
println(age) // 28
これはコンパイラが次のように展開してくれます:
val name = user.component1()
val age = user.component2()
つまり、
data class が自動で生成してくれる componentN() 関数のおかげで
簡単に分解代入できるわけです。
data class 以外でも使える?
自分で componentN() を定義すれば、独自クラスでも分解可能です。
class Point(val x: Int, val y: Int) {
operator fun component1() = x
operator fun component2() = y
}
val (x, y) = Point(10, 20)
println("$x, $y") // 10, 20
operator 修飾子が必要
componentN() は「1から始まる」命名ルールで定義
forループでの分解
for の中でも自然に使えます:
val map = mapOf("Tokyo" to "Japan", "Paris" to "France")
for ((city, country) in map) {
println("$city → $country")
}
これは実際には Map.Entry の component1()(key)と component2()(value)を使っています。
無視したい値には _ を使う
val (name, _) = User("Anna", 28)
println(name) // Anna
不要な変数は _ でスキップできます。
when と組み合わせる
val user = User("Anna", 28)
when (val (name, age) = user) {
else -> println("$name is $age years old")
}
スコープが限定されるため、when 内で安全に利用できます。
分解宣言 + 関数戻り値の利用
関数から Pair や Triple を返すときにも便利です:
fun getUserInfo(): Pair<String, Int> {
return "Anna" to 28
}
val (name, age) = getUserInfo()
println("$name is $age years old")
コレクション操作でもよく使う
mapIndexed や withIndex() と組み合わせると可読性が上がります:
val list = listOf("A", "B", "C")
for ((index, value) in list.withIndex()) {
println("$index: $value")
}
応用例:ファイル入出力など
val (lineNumber, text) = "42,Hello".split(',').let {
it[0].toInt() to it[1]
}
println("$lineNumber → $text") // 42 → Hello
まとめ
| 項目 | 説明 |
|---|---|
| 構文 | val (a, b) = obj |
| 条件 |
componentN() 関数が定義されていること |
| 代表例 |
data class, Pair, Map.Entry, IndexedValue
|
| スコープ |
for, when, val など多くの構文で利用可 |
| 無視 |
_ を使って不要な項目をスキップ |