web-dev-qa-db-ja.com

Kotlin-外部クラスのフィールドを読み取り専用にする方法

Androidに次のKotlinクラスがあります。

class ThisApplication: Application() {

    lateinit var network: INetwork

    override fun onCreate() {

        super.onCreate()

        network = Network()
    }
}

これで、外部クラスは次のようにするだけでINetwork参照を取得できます。

application.network

ただし、これにより、外部クラスがその値を上書きすることも可能になります。

application.network = myNewNetworkReference

2番目のオプションは避けたいです。残念ながら、フィールドの初期化はvalコールバック内で行う必要があるため、フィールドをonCreateにすることはできません。

また、フィールドをプライベートにして、次のような関数を使用して公開することも考えました。

private lateinit var network: INetwork
fun getNetwork() = network

ただし、getNetwork()を呼び出す人は誰でも、次のように新しい値を割り当てることができます。

application.getNetwork() = myNewNetworkReference

ネットワークフィールドを外部クラスによって読み取り専用にする方法を教えてください。またはさらに良いことに、コンストラクター内で初期化できない場合でも、それをvalにする方法はありますか?

14
Tiago

外部クラスからのアクセスを制限するために、アクセサーの可視性を変更できます。あなたの場合、privateセッターとpublicゲッターとlateinit修飾子が必要です。

_lateinit var network: INetwork
    private set
_

または、読み取り専用の遅延プロパティ:

_val network: INetwork by lazy { Network() }  //you can access private property here, eg. applicationContext
_

このコードについてあなたからいくつかの誤解があります:

_private lateinit var network: INetwork
fun getNetwork() = network
_

Kotlinはpass-by-valueであり、 Javaが行う です。したがって、application.getNetwork() = myNewNetworkReferenceは有効なステートメントではありません。関数の戻り値に値を割り当てることはできません。

25
BakaWaii

実際の変数とは別に、ゲッター/セッターの可視性を変更できます。

lateinit var network: INetwork
    private set
10
Kiskae

val network: INetwork by lazy { ... }あなたのシナリオで機能しますか?

ラムダ式は、フィールドnetworkへの最初の参照で呼び出されます。明らかに、これはOnCreateメソッドの初期化を延期することと同じではありませんが、コンストラクターで初期化せずにvalにする方法です。

他の委任の選択肢もあります。 Kotlinのドキュメント チェックする価値があります。

2
Les