はじめに
公式の問題集「Kotlin Koans」を解きながらKotlinを学習します。
過去記事はこちら
- Introduction
- Classes
- Conventions
- Collections
問題
Propertiesについて学びます。
PropertyWithCounterが割り当てられるたびにカウンタ・プロパティがインクリメントされるように、PropertyExample.propertyWithCounterにカスタム・セッターを追加してください。
class PropertyExample() {
var counter = 0
var propertyWithCounter: Int? = null
set
}
問題のポイント
Kotlinのクラスのプロパティは、varキーワードでmutableとして、またはvalキーワードでread-onlyとして宣言することができます。プロパティを使用するには、単にその名前で参照します。
fun copyAddress(address: Address): Address {
val result = Address() // there's no 'new' keyword in Kotlin
result.name = address.name // accessors are called
result.street = address.street
// ...
return result
}
プロパティに対してカスタムアクセサを定義することができます。カスタムゲッターを定義すると、そのプロパティにアクセスするたびに呼び出されます(この方法で、コンピューテッドプロパティを実装することができます)。
以下は、カスタムゲッターの例です。
class Rectangle(val width: Int, val height: Int) {
val area: Int // ゲッターの戻り値の型から推測できるので、プロパティの型は任意
get() = this.width * this.height
}
// Width=3, height=4, area=12
カスタム・セッターを定義すると、プロパティに値を代入するたびに、初期化を除いて、そのセッターが呼び出されます。カスタム・セッターは次のようなものです。
var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value) // 文字列を解析し、他のプロパティに値を代入
}
Backing fields
Kotlinでは、フィールドはプロパティの一部としてのみ使用され、その値をメモリ内に保持します。
フィールドを直接宣言することはできません。
しかし、プロパティがバッキングフィールドを必要とするとき、Kotlinは自動的にそれを提供します。
このバッキングフィールドはfield
識別子を用いてアクセサで参照することができます。
var counter = 0 // イニシャライザはバッキングフィールドを直接割り当てます。
set(value) {
if (value >= 0)
field = value
// counter = value // 実際の名前 'counter' を使用するとエラー
}
field
識別子は、プロパティのアクセッサにおいてのみ使用することができます。
バッキングフィールドは、そのプロパティが少なくともひとつのアクセサのデフォルト実装を使用しているか、カスタムアクセッサがfield
識別子を通じてそれを参照している場合に、そのプロパティに対して生成されます。
たとえば、次のような場合はバッキングフィールドは発生しません。
val isEmpty: Boolean
get() = this.size == 0
解答例
class PropertyExample() {
var counter = 0
var propertyWithCounter: Int? = null
set(value) {
field = value
counter++
}
}