はじめに
Kotlin には 拡張関数(Extension Function) と同じく、
既存のクラスに「プロパティ」を後付けできる機能、
拡張プロパティ(Extension Property) があります。
この仕組みを使うと、ライブラリや標準クラスにも新しい見た目のプロパティを追加できます。
1. 拡張プロパティとは?
拡張プロパティは、既存のクラスに新しいプロパティを追加する構文です。
ただし「状態を保持」できないため、実際はカスタム getter / setter のショートカットです。
基本構文
val String.lastChar: Char
get() = this[this.length - 1]
使用例:
println("Hello".lastChar) // → 'o'
つまり String クラスに新しい読み取り専用プロパティ lastChar を“後付け”しています。
2. 特徴まとめ
| 項目 | 内容 |
|---|---|
| 宣言方法 |
val または var にレシーバ型を指定 |
| 実体 |
get / set から計算される(値保持不可) |
| バッキングフィールド | ❌ 使用できない(field 不可) |
| 利用目的 | 既存クラスを拡張して可読性・表現力を向上 |
3. field が使えない理由
拡張プロパティは「既存クラスの外」で定義されるため、
内部状態(フィールド)を持てません。
// ❌ コンパイルエラー
var String.addedValue: String
get() = field
set(value) { field = value }
上記はエラーになります:
“Extension property cannot have a backing field”
つまり、拡張プロパティは「関数のようにその都度計算される」だけです。
4. 実用的な例①:便利な文字列処理
val String.words: List<String>
get() = this.split(" ").filter { it.isNotEmpty() }
println("Kotlin is fun".words) // → [Kotlin, is, fun]
5. 実用的な例②:Android での View 拡張
val View.isVisible: Boolean
get() = this.visibility == View.VISIBLE
var View.isGone: Boolean
get() = this.visibility == View.GONE
set(value) {
this.visibility = if (value) View.GONE else View.VISIBLE
}
使用例:
button.isGone = true
if (textView.isVisible) { ... }
📱 Jetpack Compose や Android UI 開発ではこのような拡張プロパティが多用されます。
6. 実用的な例③:inline と組み合わせる
inline 関数内でも拡張プロパティを使うと、
軽量でインライン展開される getter を実現できます。
inline val Long.kb: Long
get() = this * 1024
inline val Long.mb: Long
get() = this.kb * 1024
println(1L.mb) // → 1048576
「DSLっぽい表現」や「単位変換」などに非常に便利です。
7. 実用的な例④:Date / LocalDateTime の拡張
val LocalDateTime.formatted: String
get() = this.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
println(LocalDateTime.now().formatted)
// → 2025-10-09 18:30:00
8. var の拡張プロパティ(set付き)
var にして set() を定義することも可能ですが、
値を保持できない点には注意です。
var StringBuilder.lastChar: Char
get() = this[this.length - 1]
set(value) {
this.setCharAt(this.length - 1, value)
}
val sb = StringBuilder("Hello")
sb.lastChar = '!'
println(sb) // → Hello!
9. 応用:データクラス + 拡張プロパティでDSL風に
data class User(val name: String, val age: Int)
val User.isAdult: Boolean
get() = age >= 18
val users = listOf(User("Anna", 20), User("Taro", 16))
println(users.filter { it.isAdult }) // → [User(name=Anna, age=20)]
まとめ
| 項目 | 内容 |
|---|---|
| 定義方法 | val 型名.プロパティ名 |
| バッキングフィールド | ❌ なし |
| 使用目的 | 関数のように「動的計算プロパティ」を後付けする |
| 代表例 |
String.lastChar, View.isVisible, Long.mb
|
| 注意点 | 状態保持不可、再定義不可 |
拡張プロパティは Kotlin の「表現力の魔法」です。
単なる糖衣構文ではなく、コードの意図を可視化する手段です。
- DSL をより自然に
- Utility 関数をより宣言的に
- 外部ライブラリをより Kotlin らしく
すべてこの小さな仕組みから始まります。