web-dev-qa-db-ja.com

Kotlinプロパティのプライベートgetterおよびpublic setter

Kotlinで、プライベートゲッターを持っている(または持っていない)が、パブリックセッターを持っているプロパティを作成する方法は?

var status
private get

エラーで動作しません:Getter visibility must be the same as property visibility

私の場合、理由はJava interop:私のJavaコードがsetStatusを呼び出せるが、getStatus

36

Kotlinでは、現時点ではプロパティよりも目立つセッターを持つプロパティを持つことは不可能です。これに関する問題トラッカーには言語設計の問題がありますので、自由に見たり投票したり、ユースケースを共有してください: https://youtrack.jetbrains.com/issue/KT-311

30

現在のKotlinバージョン(1.0.3)では、唯一のオプションは、次のような個別のsetterメソッドを持つことです:

class Test {
    private var name: String = "name"

    fun setName(name: String) {
        this.name = name
    }
}

外部ライブラリがゲッターにアクセスすることを制限したい場合、 internal 可視性修飾子を使用して、ライブラリ内でプロパティ構文を引き続き使用できます。

class Test {
    internal var name: String = "name"
    fun setName(name: String) { this.name = name }
}

fun usage(){
    val t = Test()
    t.name = "New"
}
24
miensol

コンパイル時エラーを伴う書き込み専用プロパティcanは、Kotlin 1.0以降、_@Deprecated_に基づく回避策を使用して実現されます。

実装

Kotlinでは、非推奨の関数をレベルERRORでマークできます。これにより、呼び出し時にコンパイル時エラーが発生します。プロパティのgetアクセサーにerror-deprecatedとして注釈を付け、バッキングフィールドと組み合わせて(プライベート読み取りが可能になるように)、目的の動作を実現します。

_class WriteOnly {
    private var backing: Int = 0

    var property: Int
        @Deprecated("Property can only be written.", level = DeprecationLevel.ERROR)
        get() = throw NotImplementedError()
        set(value) { backing = value }

    val exposed get() = backing // public API
}
_

使用法:

_val wo = WriteOnly()
wo.property = 20         // write: OK

val i: Int = wo.property // read: compile error
val j: Int = wo.exposed  // read value through other property
_

コンパイルエラーも非常に役立ちます。

「プロパティのゲッター:Int」を使用するとエラーになります。プロパティは書き込みのみ可能です。


ユースケース

  1. 主な使用例は、明らかにプロパティの書き込みは許可するが読み取りは許可しないAPIです。

    _user.password = "secret"
    val pw = user.password // forbidden
    _
  2. 別のシナリオは、内部状態を変更するプロパティですが、それ自体はフィールドとして保存されません。 (異なるデザインを使用してよりエレガントに行うことができます)。

    _body.thrust_force = velocity
    body.gravity_force = Vector(0, 0, 9.8)
    // only total force accessible, component vectors are lost
    val f = body.forces
    _
  3. このパターンは、次の種類のDSLにも役立ちます。

    _server {
        port = 80
        Host = "www.example.com"
    }
    _

    このような場合、値は単に1回限りの設定として使用され、ここで説明する書き込み専用メカニズムは、プロパティ(まだ初期化されていない可能性がある)を誤って読み取ることを防ぐことができます。


制限事項

この機能はこのユースケース向けに設計されていないため、特定の制限があります。

  • プロパティ参照を使用してアクセスすると、コンパイル時エラーはランタイムエラーに変わります。

    _val ref = wo::property
    val x = ref.get() // throws NotImplementedError
    _
  • 反射についても同じことが言えます。

  • error-deprecatedgetValue()メソッドはbyと共に使用できないため、この機能をデリゲートにアウトソースすることはできません。 。

1
TheOperator