0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Kotlin】Kotlin 拡張プロパティ(Extension Property)徹底解説

Posted at

はじめに

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 らしく

すべてこの小さな仕組みから始まります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?