Destructuring declaration(分解宣言)は、オブジェクトを1つの式で複数の変数に分解できるKotlinの機能です。val (name, age) = user構文は、2つの変数を同時に宣言し、オブジェクトのコンポーネントから値を割り当てます。Kotlinドキュメント(2026年)によると、data classを扱う際、分解によりコード量が30~50%削減されます。Destructuring declarationはコードをより簡潔で読みやすくします。
主なポイント
val (a, b) = objDestructuring declaration(分解宣言)は、クラスインスタンスを1つの式で複数の変数に分解できるKotlinの構文構造です。左側には括弧で囲まれた変数のリスト、右側には分解されるオブジェクトが含まれます。Kotlinは各変数に対して対応するcomponentN()関数(Nは括弧内の変数の順序番号)を自動的に呼び出します。
分解宣言は主にdata classと共に使用されます。Kotlinコンパイラは、プライマリコンストラクタのプロパティ数に基づいて、各data classに対してcomponent1()、component2()などを自動的に生成します。data修飾子のない通常のクラスでは、componentN()は生成されませんが、operatorキーワードを使用して手動で定義できます。
分解宣言は、ペアのコレクション、関数の結果、Mapの反復処理を扱う際にコードを簡素化できることから、人気のあるパターンになっています。person.firstNameやperson.lastNameと書く代わりに、開発者はval (firstName, lastName) = personと記述します。これにより、行数が減り、特にループやラムダでの可読性が向上します。
val (a, b) = obj構文に遭遇すると、Kotlinコンパイラは次のコードを生成します:val a = obj.component1()、val b = obj.component2()。変数がvarで宣言されている場合、var代入が生成されます。各変数の型は、対応するcomponentN()関数の戻り値の型から推論されます。つまり、分解宣言は完全に型安全であり、コンパイル時にチェックされます。
data class Person(val firstName: String, val lastName: String, val age: Int)
fun main() {
val person = Person("Alice", "Smith", 30)
// 分解: component1()、component2()、component3()
val (firstName, lastName, age) = person
println("$firstName $lastName、$age 歳")
}
リストでは、Personは3つのプロパティを持つdata classです。Kotlinはcomponent1() → firstName、component2() → lastName、component3() → ageを生成します。式val (firstName, lastName, age) = personはこれらの関数を呼び出し、結果を割り当てます。重要な点:変数名はプロパティ名と一致する必要はありません — コンパイラはcomponentN()の順序とその型のみを確認します。最初のN個のプロパティのみを分解し、残りは無視できます。
Data classesは分解宣言の主要な候補です。各data classは、プライマリコンストラクタのすべてのプロパティに対して自動的にcomponentN()を取得します。componentN()の順序はプロパティ宣言の順序に対応します。つまり、data classでフィールドの順序を変更すると、分解での変数の順序も変わり、微妙なバグにつながる可能性があります。
// Pairの分解
val pair = Pair("key", 42)
val (key, value) = pair
println("$key -> $value")
// Tripleの分解
val triple = Triple("A", "B", "C")
val (first, second, third) = triple
// ループ内のMap.Entry
val map = mapOf("a" to 1, "b" to 2)
for ((k, v) in map) {
println("$k = $v")
}
PairとTripleは、2つと3つのコンポーネントに対して組み込みの分解を備えた標準クラスです。Pairは、個別のdata classを作成せずに関連する2つの値を返す必要がある関数の戻り値の型としてよく使用されます。Map.Entryのforループでは、(k, v) = entry構文がcomponent1()とcomponent2()を介してキーと値を分解します。これはKotlinでMapを反復処理する標準的なパターンであり、keyとvalueの明示的な呼び出しを完全に置き換えます。
分解中に一部のコンポーネントが不要な場合、Kotlinではそれらをアンダースコア_で置き換えることができます。これにより可読性が向上します — 読者はそのコンポーネントが無視されていることをすぐに理解できます。さらに、_を使用すると、初期化されていない変数への誤ったアクセスを防げます:コンパイラは_に対して変数を作成しないため、未使用変数に関する警告がなくなります。
data class Order(
val id: Long,
val customerName: String,
val amount: Double,
val status: String
)
fun process(orders: List<Order>) {
for ((id, _, amount) in orders) {
println("注文 $id: $amount")
}
}
リストでは、Orderに4つのプロパティがありますが、ループに必要なのはidとamountだけです。customerNameの代わりのアンダースコアは、コンパイラに「component2()をスキップ」と指示します。Kotlinはcomponent2()を呼び出さず、このコンポーネントの変数も作成しません。重要:アンダースコアは分解宣言でのみ使用でき、data classコンストラクタでは使用できません。連続する複数のコンポーネントがスキップされる場合、それぞれに独自のアンダースコアが割り当てられます。
data修飾子のないクラスの場合、operatorキーワードを追加して手動でcomponentN()を定義できます。これにより、ソースコードを変更できないサードパーティのクラスを含む、任意のクラスで分解宣言を使用できます — operatorを使用した拡張関数を記述するだけです。このアプローチは、自動componentN()を持たないライブラリクラスやJavaクラスに特に役立ちます。
class Rect(val width: Int, val height: Int)
operator fun Rect.component1(): Int = width
operator fun Rect.component2(): Int = height
// gettersを持つJavaクラスの場合
operator fun Dimension.component1(): Int = width
operator fun Dimension.component2(): Int = height
fun main() {
val rect = Rect(1920, 1080)
val (w, h) = rect
println("解像度: ${w}x${h}")
}
例では、Rectはdataのない通常のクラスです。operator fun component1() = widthとcomponent2() = heightを持つ拡張関数が、分解サポートを追加します。同様にjava.awt.Dimensionの場合:Dimensionに対するoperator拡張により、widthとheightに分解できます。制限:分解宣言のコンポーネントの最大数は5です。理論的にはcomponent6()以上を定義できますが、Kotlinは括弧内の6つ以上の変数に対応する構文を生成しません。
よくある質問
はい、すべてのdata classはプライマリコンストラクタのすべてのプロパティに対して自動的にcomponentN()を取得します。クラス本体で宣言されたプロパティ(val/varなしのコンストラクタパラメータを使用)はcomponentN()を生成しません。
val (a, b, c) = objのオブジェクトが2つのcomponent関数しか持たない場合、コンパイラはエラーを出力します。変数が少ない場合(val (a) = pair)、Kotlinはcomponent1()のみを呼び出し、component2()を無視します — エラーは発生しません。
はい、Map.Entryは分解をサポートしています:val (key, value) = map.entries.first()。Map全体を一度に分解することはできません — forループまたはイテレータを使用して要素ごとにのみ分解できます。
はい、Kotlinはラムダパラメータでの分解をサポートしています:map.forEach { (k, v) -> ... }。ラムダパラメータ内のdata classには、パラメータを囲む入れ子の括弧を追加する必要があります。
Kotlinは分解宣言で最大5つの変数をサポートしています。5つ以上のプロパティを分解する必要がある場合は、それらを入れ子のdata classに結合するか、単一の変数内でPair/Tripleを使用してください。
まとめ
val (a, b) = obj、オブジェクトを1つの式で複数の変数に分解ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。