データクラス
何もしない、データを保持するためだけのクラスを作成することはよくあります。そのようなクラスでは、いくつかの標準機能は、データから機械的に推論できます。Kotlinでは、これは データクラス と呼ばれ、 data
としてマークされています。
data class User(val name: String, val age: Int)
プライマリコンストラクタで宣言されたすべてのプロパティから、コンパイラは自動的に次のメンバを推論します:
equals()
/hashCode()
のペア、"User(name=John, age=42)"
形式のtoString()
、- 宣言した順番でプロパティに対応する
componentN()
関数、 copy()
関数(下記参照)。
これらの機能のいずれかが明示的にクラス本体に定義されているか、基本型から継承されている場合は、生成されません。
生成されたコードの一貫性と意味のある動作を保証するために、データクラスは、次の要件を満たさなければなりません:
- プライマリコンストラクタは、少なくとも1つのパラメータを持っている必要があります。
- すべてのプライマリコンストラクタのパラメータは、
val
またはvar
としてマークする必要があります。 - データクラスは、 abstract, open, sealed または inner にすることはできません。
- データクラスは他のクラスを拡張しない場合があります(ただし、インターフェイスを実装することはできます)。
JVM上で、生成されたクラスがパラメータなしのコンストラクタを持つ必要がある場合は、すべてのプロパティのデフォルト値を指定する必要があります(コンストラクタを参照してください)。
data class User(val name: String = "", val age: Int = 0)
コピー
プロパティの いくつか を変更し、残りをそのままにしてオブジェクトをコピーする、ということが必要になるのはよくあることです。これが copy()
関数が作成される理由です。次のような User
クラスの場合、その実装は次のようになります。
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
これは次のように書くことができます:
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
データクラスと分解宣言 (Destructuring Declarations)
データクラスのために生成した コンポーネント関数 は、分解宣言内で使用できます。
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // "Jane, 35 years of age" を出力する
標準データクラス
標準ライブラリは、 Pair
と Triple
を提供します。プロパティのために意味のある名前を提供することにより、コードを読みやすくするため、というのが理由です。ほとんどのケースでは、名前付きデータクラスは、設計上のより良い選択ですが。