Kotlin идиоматический способ пересылки имущества из другого класса - PullRequest
1 голос
/ 13 апреля 2019

Как в примере:

class A {    
    var value: String
    get() = "value"
    set(value) { println(value) }
}

class B {
    val a = A()
    var value = a.value
}

fun main(args: Array<String>) {
    B().value = "new value"
}

B.value инициализируется только с A.value.get, поэтому, конечно, A.value.set не вызывается во время назначения в функции main, и, следовательно, не выводит сообщение на консоль.

Я ищу синтаксис, который позволял бы пересылать функции get и set в новую переменную на основе свойства другого объекта того же типа.

Мне удалось реализовать такой делегат, но он опирается на библиотеку kotlin-рефлекса (вызывая getter и setter), и я хотел бы избежать этого:

import kotlin.reflect.KProperty
import kotlin.reflect.KMutableProperty

class Forward<T> (private val originalProperty: KProperty<T>){
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return originalProperty.getter.call()
    }
}

class ForwardMutable<T> (private val originalProperty: KMutableProperty<T>){
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        originalProperty.setter.call(value)
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return originalProperty.getter.call()
    }
}

fun <T> forward(originalProperty: KProperty<T>) = Forward(originalProperty)
fun <T> forward(originalProperty: KMutableProperty<T>) = ForwardMutable(originalProperty)

class A {
    var value: String
        get() = "value"
        set(value) { println(value) }
}

class B {
    val a = A()
    var value by forward(a::value)
}

fun main(args: Array<String>) {
    B().value = "new value" // calls A.value.setter
}

Нет ли для этой цели встроенного делегата? Если нет, как я могу избежать kotlin-reflect зависимости?

Ответы [ 2 ]

0 голосов
/ 13 апреля 2019

Может быть, я что-то неправильно понимаю, но, если вы можете извлечь интерфейс переменных, которые вы хотите делегировать внутреннему экземпляру, то почему бы просто не использовать делегаты?

interface SomethingWithValues{
    var value: String
    var value2: String
    var value3: String
}

class A : SomethingWithValues{
    override var value: String = "value"
        set(value) {print(value)}
    override var value2: String = "value2"
        set(value) {print(value)}
    override var value3: String = "value3"
        set(value) {print(value)}
}

class B(val a:A = A()): SomethingWithValues by a

fun main(args: Array<String>) {
    val b = B()
    b.value = "new value"
    b.value2 = "new value2"
    b.value3 = "new value3"
}
0 голосов
/ 13 апреля 2019

Если thisRef должен быть таким же общим, как Any, тогда я не думаю, что вы можете получить доступ к его свойствам без отражения.

Если вы хотите ввести дополнительные интерфейсы, вы, вероятно, могли бы сделать что-то вроде этого: (все еще существует зависимость импорта от kotlin.reflect, но это требуется для Delegate API)

import kotlin.reflect.KProperty

interface HasA<T> {
    val a: ValueAccessor<T>
}

interface ValueAccessor<T> {
    var value: T
}

class ForwardMutable<T> {
    operator fun setValue(thisRef: HasA<T>, property: KProperty<*>, value: T) {
        thisRef.a.value = value
    }

    operator fun getValue(thisRef: HasA<T>, property: KProperty<*>): T {
        return thisRef.a.value
    }
}

class A : ValueAccessor<String> {
    override var value: String = "value"
}

class B : HasA<String> {
    override val a = A()
    var value by ForwardMutable<String>()
}

fun main(args: Array<String>) {
    val b = B()
    b.value = "new value" // calls A.value.setter
    print(b.value)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...