Kotlin DSL - Generi c лямбда с несколькими приемниками - PullRequest
1 голос
/ 28 апреля 2020

Я создаю DSL для своего проекта, и я действительно хочу иметь возможность использовать поля / методы из нескольких получателей, не вкладывая их:

Например:

class Foo {
    val fooField = "Foo field"
}

class Bar {
    val barField = "Bar field"
}

fun main() {

    val foo = Foo()
    val bar = Bar()

    (foo..bar) {
        println(fooField)
        println(barField)
    }

}

Вместо :

class Foo {
    val fooField = "Foo field"

    operator fun invoke(block: Foo.() -> Unit) {
        block(this)
    }
}

class Bar {
    val barField = "Bar field"

    operator fun invoke(block: Bar.() -> Unit) {
        block(this)
    }
}

fun main() {

    val foo = Foo()
    val bar = Bar()

    foo {
        bar {
            println(fooField)
            println(barField)    
        }
    }
}

Я думал о чем-то вроде:

class Buzz<T1, T2>(
    val t1: T1,
    val t2: T2
) {

    operator fun invoke(function: /* T1 + T2*/ () -> Unit) { // <--- ???
        function(/* t1 + t2*/)
    }
}

operator fun <T, R> T.rangeTo(r: R): Buzz<T, R> {
    return Buzz(this, r)
}

Но можно ли как-то объединить два приемника без шаблонного?

1 Ответ

0 голосов
/ 28 апреля 2020

Вы не можете сделать это просто потому, что одна переменная не может содержать ссылку на два объекта одновременно.

Но похожим решением может быть использование пары, она может относиться * с вашей проблемой:

val foo = Foo()
val bar = Bar()

Pair(foo,bar).apply {         // this: Pair<Foo, Bar>
    println(first.fooField)
    println(second.barField)
}

Примечание *: Это всего лишь предложение как it does remove boilerplate by nested lambdas, но с другой стороны, не дает решения с lambda with multiple receivers

...