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?

More than 1 year has passed since last update.

第35回:Delegates example

Posted at

はじめに

公式の問題集「Kotlin Koans」を解きながらKotlinを学習します。

過去記事はこちら

問題

Delegates example

デリゲートプロパティについて学び、デリゲートを使ってプロパティを遅延させます。

修正前コード.kt
class LazyProperty(val initializer: () -> Int) {
    val lazyValue: Int by TODO()
}

問題のポイント

一般的なプロパティの中には、必要な都度手動で実装してもよいものがありますが、一度実装してライブラリに追加し、後で再利用する方が便利です。例えば

  • レイジープロパティ:最初のアクセス時のみ値が計算される。
  • Observableプロパティ:このプロパティの変更についてリスナーに通知される。
  • 各プロパティに対して個別のフィールドを用意するのではなく、マップにプロパティを格納する。

これらの(そして他の)ケースをカバーするために、Kotlinはデリゲートプロパティをサポートしています。

class Example {
    var p: String by Delegate()
}

構文としては、val/var <プロパティ名>:<Type> by <expression>です。
byの後の式はデリゲートです。なぜなら、プロパティに対応するget()set()は、そのgetValue()setValue()メソッドにデリゲートされることになるからです。
プロパティのデリゲートはインターフェースを実装する必要はありませんが、getValue()varsの場合はsetValue())を提供する必要があります。

import kotlin.reflect.KProperty

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}

Delegateのインスタンスに委譲されたpから読み込むとき、DelegategetValue()関数が呼び出されます。
その第一引数にはpを読み込んだオブジェクトが、第二引数にはp自身の説明(例えば、名前を取る)が入ります。

val e = Example()
println(e.p) // Example@33a17727, thank you for delegating 'p' to me!

同様に、pに代入する場合は、setValue()関数が呼び出されます。
最初の2つのパラメータは同じもので、3つ目のパラメータには代入される値が格納されます。

e.p = "NEW"
// NEW has been assigned to 'p' in Example@33a17727.

Lazy properties

Kotlinの標準ライブラリは、いくつかの便利な種類のデリゲートのためのファクトリーメソッドを提供します。
lazy() はラムダを受け取り、Lazy のインスタンスを返す関数で、遅延プロパティを実装するためのデリゲートとして使用することができます。
get() の最初の呼び出しは、lazy() に渡されたラムダを実行し、その結果を記憶しています。それ以降の get() の呼び出しは、単に記憶された結果を返します。

val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main() {
    println(lazyValue)
    println(lazyValue)
}
// computed!
// Hello
// Hello

解答例

class LazyProperty(val initializer: () -> Int) {
    val lazyValue: Int by lazy(initializer)
}
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?