簡體   English   中英

使用沒有 setter 的委托創建 var

[英]Create a var using a delegate that does not have a setter

我正在嘗試使用不提供setValue(...)方法的委托創建委托 var 屬性。 換句話說,我需要一個可以重新分配的屬性,但只要它沒有被重新分配,它就應該通過委托獲取它的值。

我正在使用使用委托的xenomachina CLI arguments 解析器庫。 只要我有val屬性,這就會很好地工作。 在某些情況下,我需要能夠在運行時動態更改這些屬性,但需要一個可變的var 我不能在這里簡單地使用var ,因為該庫在其負責參數解析的委托中沒有提供setValue(...)方法。

理想情況下,我想要這樣的東西:

class Foo(parser: ArgParser) {
    var myParameter by parser.flagging(
        "--my-param",
        help = "helptext"
    )
}

由於缺少二傳手,這不起作用。

到目前為止,我已經嘗試使用 setter 擴展 function 擴展Delegate class,但在內部它也使用val ,所以我無法更改。 我嘗試將委托包裝到另一個委托中,但是當我這樣做時,庫將無法識別我已經包裝的選項。 雖然我可能在那里錯過了一些東西。 我不能只是將值重新分配給新的 var,如下所示:

private val _myParameter by parser.flagging(...)
var myParameter = _myParameter

因為這似乎使解析器感到困惑,並且一旦訪問第一個委托屬性,它就會停止評估參數的 rest。 此外,它不是特別漂亮。

您如何使用不包含 setter 和var屬性的委托?

以下是如何包裝ReadOnlyProperty以使其按您想要的方式工作:

class MutableProperty<in R, T>(
    // `(R, KProperty<*>) -> T` is accepted here instead of `ReadOnlyProperty<R, T>`,
    // to enable wrapping of properties which are based on extension function and don't
    // implement `ReadOnlyProperty<R, T>`
    wrapped: (R, KProperty<*>) -> T
) : ReadWriteProperty<R, T> {
    private var wrapped: ((R, KProperty<*>) -> T)? = wrapped // null when field is assigned
    private var field: T? = null

    @Suppress("UNCHECKED_CAST") // field is T if wrapped is null
    override fun getValue(thisRef: R, property: KProperty<*>) =
        if (wrapped == null) field as T
        else wrapped!!(thisRef, property)

    override fun setValue(thisRef: R, property: KProperty<*>, value: T) {
        field = value
        wrapped = null
    }
}

fun <R, T> ReadOnlyProperty<R, T>.toMutableProperty() = MutableProperty(this::getValue)

fun <R, T> ((R, KProperty<*>) -> T).toMutableProperty() = MutableProperty(this)

用例:

var lazyVar by lazy { 1 }::getValue.toMutableProperty()

以下是包裝屬性委托提供者的方法:

class MutableProvider<in R, T>(
    private val provider: (R, KProperty<*>) -> (R, KProperty<*>) -> T
) {
    operator fun provideDelegate(thisRef: R, prop: KProperty<*>): MutableProperty<R, T> =
        provider(thisRef, prop).toMutableProperty()
}

fun <T> ArgParser.Delegate<T>.toMutableProvider() = MutableProvider { thisRef: Any?, prop ->
    provideDelegate(thisRef, prop)::getValue
}

用例:

var flagging by parser.flagging(
    "--my-param",
    help = "helptext"
).toMutableProvider()

您可以使用 class 包裝您的委托,如下所示:

class DefaultDelegate<T>(private val default: Delegate<T>){
    private var _value: T? = null

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T? = 
        _value?: default.value

    operator fun setValue(thisRef: Nothing?, property: KProperty<*>, value: T?) {
        _value = value
    }
}

用法:

class Foo(parser: ArgParser) {
    var myParameter: Boolean? by DefaultDelegate(parser.flagging(
        "--my-param",
        help = "helptext"
    ))
}

如果您需要可空性:

class DefaultDelegate<T>(private val default: Delegate<T>){
    private var modified = false
    private var _value: T? = null

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T? = 
        if (modified) _value else default.value

    operator fun setValue(thisRef: Nothing?, property: KProperty<*>, value: T?) {
        _value = value
        modified = true
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM