Kotlinで「by」キーワードは何をしますか?


回答:


76

Kotlin参照あなたがのために2つの用途を見つけるだろうby、最初のもの委任プロパティあなたは上に持って使用することです。

特定の一般的な種類のプロパティがあります。これらは必要なときに手動で実装できますが、一度だけ実装してライブラリに入れると非常に便利です。例としては、レイジープロパティがあります。値は最初のアクセス時にのみ計算されます。監視可能なプロパティ:リスナーは、このプロパティの変更について通知を受け取り、プロパティをそれぞれ個別のフィールドではなくマップに保存します。

ここでは、ゲッター/セッターを、作業を実行し、共通のコードを含めることができる別のクラスに委任します。別の例として、Kotlinの依存性注入器の一部は、依存性注入エンジンによって管理されるインスタンスのレジストリから値を受け取るようにゲッターを委任することで、このモデルをサポートしています。

そして、インターフェース/クラスの委任は他の用途です:

委任パターンは、実装の継承に代わる優れた方法であることが証明されており、Kotlinは、ボイラープレートコードをゼロにする必要があるネイティブパターンをサポートしています。Derivedクラスは、インターフェイスBaseから継承し、そのすべてのパブリックメソッドを指定されたオブジェクトに委任できます。

ここで、インターフェイスを別の実装に委任できるため、実装クラスは変更したいものをオーバーライドするだけで済み、残りのメソッドはより完全な実装に委任されます。

実例は、Klutter Readonly / Immutableコレクションです。で、実際には特定のコレクションインターフェイスを別のクラスに委任し、読み取り専用の実装で異なる必要があるものをすべてオーバーライドします。他のすべてのメソッドを手動で委任する必要がないため、多くの作業を節約できます。

これらは両方ともKotlin言語リファレンスカバーされており、言語の基本トピックから始めます。


93

簡単に言えば、によって提供されるbyキーワードを理解することができます。

不動産消費者の観点からは、valゲッター(get)varを持つものであり、ゲッターとセッター(get、set)を持つものです。それぞれについてvarプロパティに、明示的に指定する必要のないgetメソッドとsetメソッドのデフォルトプロバイダーがあります。

ただし、byキーワードを使用する場合は、このgetter / getter&setterが他の場所で提供されている(つまり、委任されている)ことを示しています。の後に続く関数によって提供さbyます。

したがって、この組み込みのgetメソッドとsetメソッドを使用する代わりに、そのジョブを明示的な関数に委任します。

非常に一般的な例の1つは、by lazy遅延読み込みプロパティの場合です。また、Koinのような依存性注入ライブラリを使用している場合は、次のように定義された多くのプロパティが表示されます。

var myRepository: MyRepository by inject()  //inject is a function from Koin

クラス定義では、同じ原則に従い、関数が提供される場所を定義しますが、getとsetだけでなく、メソッド/プロパティの任意のセットを参照できます。

class MyClass: SomeInterface by SomeImplementation, SomeOtherInterface

このコードは次のように言っています。 '私はクラスMyClassであり、SomeImplementationによって提供されるインターフェイスSomeInterfaceの関数を提供します。SomeOtherInterfaceを自分で実装します(これは暗黙的であるため、byありません)。


23

ここに画像の説明を入力してください

構文は次のとおりです。

val/var <property name>: <Type> by <expression>. 

byの後の式はデリゲートです

我々は、プロパティの値にアクセスしようとした場合のpを我々が呼び出した場合、他の言葉で、()を取得財産の法PのgetValue()のメソッドのデリゲートをのインスタンスが起動されます。

私たちは、プロパティの値を設定しようとした場合のpを我々が呼び出した場合、他の言葉で、セット()プロパティの方法PをのsetValue()のメソッドデリゲートインスタンスが呼び出されます。


7

プロパティの委任:

import kotlin.reflect.KProperty

class Delegate {
    // for get() method, ref - a reference to the object from 
    // which property is read. prop - property
    operator fun getValue(ref: Any?, prop: KProperty<*>) = "textA"
    // for set() method, 'v' stores the assigned value
    operator fun setValue(ref: Any?, prop: KProperty<*>, v: String) {
        println("value = $v")
    }
}

object SampleBy {
    var s: String by Delegate() // delegation for property
    @JvmStatic fun main(args: Array<String>) {
        println(s)
        s = "textB"
    }
}

結果:

textA
value = textB

クラスの委任:

interface BaseInterface {
    val value: String
    fun f()
}

class ClassA: BaseInterface {
    override val value = "property from ClassA"
    override fun f() { println("fun from ClassA") }
}

// The ClassB can implement the BaseInterface by delegating all public 
// members from the ClassA.
class ClassB(classA: BaseInterface): BaseInterface by classA {}

object SampleBy {
    @JvmStatic fun main(args: Array<String>) {
        val classB = ClassB(ClassA())
        println(classB.value)
        classB.f()
    }
}

結果:

property from ClassA
fun from ClassA

パラメータの委任:

// for val properties Map is used; for var MutableMap is used
class User(mapA: Map<String, Any?>, mapB: MutableMap<String, Any?>) {
    val name: String by mapA
    val age: Int by mapA
    var address: String by mapB
    var id: Long by mapB
}

object SampleBy {
    @JvmStatic fun main(args: Array<String>) {
        val user = User(mapOf("name" to "John", "age" to 30),
        mutableMapOf("address" to "city, street", "id" to 5000L))

        println("name: ${user.name}; age: ${user.age}; " +
        "address: ${user.address}; id: ${user.id}")
    }
}

結果:

name: John; age: 30; address: city, street; id: 5000
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.