プロパティに関する変更点
最後に紹介するのは、プロパティに関する変更点です。
ゲッタの省略記述
Kotlinのプロパティとは、単なる変数ではありません。データに対するゲッタとセッタ(アクセサ)が自動生成される仕組みです。このことから、プロパティのセッタやゲッタをカスタマイズできるようになっています。
また、データを持たないゲッタのみのプロパティ、つまり算出プロパティ(Computed Property)を定義することもできます。
例えば、リスト15の(1)のようなコードです。
data class GinBaseCocktail( val name: String, val ginVolume: Int ) { val ginVolumeStr: String // (1) get() { // (1) return "${ginVolume}ml" // (1) } // (1) }
リスト15の(1)で定義したginVolumeStrプロパティには、その実体(データ本体)が存在せず、プロパティへのアクセスは、その都度ginVolumeプロパティを元に算出された文字列がリターンされます。
ゲッタの{ }ブロック内のコードが(1)のように1行のみの場合は、代入式が利用でき、次のコードとすることができます。いわゆる、単一式関数(Single-Expression Functions)の構文です。
val ginVolumeStr: String get() = "${ginVolume}ml"
さらに、こういった単一式関数のゲッタの場合、プロパティの型への型推論が働き、型宣言が省略できるようにバージョン1.1で変更されています。
これを利用すると、ginVolumeStr算出プロパティは、次の1行で記述できます。
val ginVolumeStr get() = "${ginVolume}ml"
インラインプロパティ
同じく、バージョン1.1で導入されたのがインラインプロパティです。インライン関数については前回紹介しました。
インラインプロパティは、このインライン関数と同じ機能をプロパティのアクセサに適用できるものです。すなわち、コンパイル段階でアクセサのコードを埋め込むことができます。
定義方法もインライン関数と同じく、inlineキーワードを使います。例えば、リスト16の(2)のようなコードとなります。
data class BourbonBaseCocktail( val name: String, // (1) val bourbonVolume: Int // (1) ) { inline val ginVolumeStr get() = "${bourbonVolume}ml" // (2) }
ただし、このインラインプロパティを定義できるのは、バッキングフィールドを持たないプロパティに限る点に注意しましょう。
バッキングフィールド(Backing Field)とは、プロパティのデータを保持しているプロパティの実体のことで、通常、表には顔を出しません。
例えば、リスト16の(1)のようなプロパティを宣言した場合、その内部では名前とバーボンの量を保持するプロパティの実体(データ本体)とそのアクセサが自動生成されていることになり、このデータ本体がバッキングフィールドです。
一方、(2)の算出プロパティは、前項で説明した通りデータ本体が存在しません。これは、バッキングフィールドが存在しないプロパティです。このようなプロパティのみ、インライン化できます。
そのため、リスト16の(1)に対してinlineキーワードを記述すると、エラーになるので注意してください。
※エラーとなるのはバージョン2.1以降です。それ以前のバージョンの環境では警告のみ表示されます。
まとめ
Kotlinのバージョン2.0までに導入された新機能をテーマごとに紹介する本連載の第3回目は、いかがでしたでしょうか。
今回は、クラスとインターフェースに関するアップデートというテーマで、sealed、data、プロパティに関する変更点を紹介しました。次回は、この続きとして、委譲プロパティやインラインクラス、Enumに関する変更点を紹介します。