🫖

Kotlinの分解宣言を使うとJavaScriptの分割代入っぽく書けるよ

2025/01/06に公開

JavaScriptの分割代入とは?

誰しも書いたことがあるであろうこれのことです。

const obj = {a:0, b:1};
const { a, b } = obj;

// これは以下のものと同様です
// const a = obj.a;
// const b = obj.b;

Kotlinの分割宣言とは?

以下のようなコードのことです。operator fun componentN()のように記述します。

class Data(val firstName: String, val lastName: String, val age: Int, val sex: Int){
    operator fun component1() = firstName
    operator fun component2() = lastName
    operator fun component3() = age
    operator fun component4() = sex
}

結果、このように分割代入することができます。

fun main() {
    val data = Data("hoge", "fuga", 20, 1)
    val (firstname) = data
    println(firstname) // hoge
}

Pair...??

この分割代入の記法を見た時、「Pair...?」や「Triple...?」と思われた方もいらっしゃるでしょう。

ではPairoperator fun componentN()のように書かれているのでしょうか?

実装を見てみます。すると…

public data class Pair<out A, out B>(
    public val first: A,
    public val second: B
) : Serializable {

    /**
     * Returns string representation of the [Pair] including its [first] and [second] values.
     */
    public override fun toString(): String = "($first, $second)"
}

そんなことはなく、単にdata classとして宣言されています。これはどういうことでしょうか?

data classを用いた分割宣言

そう、実はdata classの内部ではoperator fun componentN()は自動で生成されるようになっています。

つまり、以下のコードと先ほどのclass Dataは同じように使うことができます。

data class Data(val firstName: String, val lastName: String, val age: Int, val sex: Int)

fun main() {
    val data = Data("hoge", "fuga", 20, 1)
    val (firstname) = data
    println(firstname)
}

おわり

ではどう使い分けるのがいいだろうか?という話ですが、これはclassdata classの性質によるかと思います。

classでデータを持ちつつも、そのデータを加工して保持するproccessor的なsetterが必要な場合は、operator fun componentN()として持ってあげると良いかもしれません。

逆にDTOのように、単に値を持ち回したいだけ という場面では普通にdata classを扱う方がシンプルかつ実装量が少なく済んで良さそうです。

Discussion