Есть ли способ сохранить типы в параметре vararg? - PullRequest
0 голосов
/ 24 апреля 2019

Мой вопрос: можно сделать что-то вроде:

fun <T, R> someFunction(vararg sources<out T>, doSomething: (vararg sources<out T>) -> R) {
    // do something here
}

Так что, если я сделаю что-то вроде:

someFunction(SomeType<A>(), SomeType<B>(), SomeType<C>()) { a: A, b: B c: C ->
    // do Something
}

Как правило, для функции более высокого порядка требуются все типы параметров.

Причина, по которой я спрашиваю это, заключается в том, что я хотел бы упростить код, подобный следующему:

inline fun <T1, T2, R> MediatorLiveData<out R>.merge(source1: LiveData<out T1>, source2: LiveData<out T2>, crossinline merger: (T1?, T2?) -> R?) {
    addSource(source1) {
        this.value = merger.invoke(source1.value, source2.value)
    }
    addSource(source2) {
        this.value = merger.invoke(source1.value, source2.value)
    }
}

inline fun <T1, T2, T3, R> MediatorLiveData<out R>.merge(source1: LiveData<out T1>, source2: LiveData<out T2>, source3: LiveData<out T3>, crossinline merger: (T1?, T2?, T3?) -> R?) {
    addSource(source1) {
        this.value = merger.invoke(source1.value, source2.value, source3.value)
    }
    addSource(source2) {
        this.value = merger.invoke(source1.value, source2.value, source3.value)
    }
    addSource(source3) {
        this.value = merger.invoke(source1.value, source2.value, source3.value)
    }
}

inline fun <T1, T2, T3, T4, R> MediatorLiveData<out R>.merge(source1: LiveData<out T1>, source2: LiveData<out T2>, source3: LiveData<out T3>, source4: LiveData<out T4>, crossinline merger: (T1?, T2?, T3?, T4?) -> R?) {
    addSource(source1) {
        this.value = merger.invoke(source1.value, source2.value, source3.value, source4.value)
    }
    addSource(source2) {
        this.value = merger.invoke(source1.value, source2.value, source3.value, source4.value)
    }
    addSource(source3) {
        this.value = merger.invoke(source1.value, source2.value, source3.value, source4.value)
    }
    addSource(source4) {
        this.value = merger.invoke(source1.value, source2.value, source3.value, source4.value)
    }
}

Может кто-нибудь предложить что-нибудь? Заранее спасибо!

1 Ответ

1 голос
/ 24 апреля 2019

Попробуйте следующую функцию:

fun <T, R> someFunction(vararg sources: LiveData<out T>, doSomething: (sources: Array<out LiveData<out T>>) -> R) {
    // ...

    doSomething(sources)
}

Кажется, мы не можем использовать модификатор vararg в лямбда-выражении doSomething, замена его на Array будет работать.

EDIT: Таким образом, в основном вы сможете сделать что-то вроде следующего для разного количества источников без создания дополнительных функций, как в вашем примере:

fun <T, R> someFunction(vararg sources: LiveData<out T>, doSomething: (sources: Array<out LiveData<out T>>) -> R) {
    sources.forEach {
        addSource(it) {
            doSomething.invoke(sources)
        }
    }
}

// Call someFunction with different number of args:
val l1: LiveData<Int> = MutableLiveData()
val l2: LiveData<String> = MutableLiveData()
val l3: LiveData<String> = MutableLiveData()

// Call with two args:
someFunction(l1, l2) { sources: Array<out LiveData<out Any>> ->
    val data1 = sources[0] as LiveData<Int>
    val data2 = sources[1] as LiveData<String>
    // do your work here   
}
// Or Call with three args:
someFunction(l1, l2, l3) { sources: Array<out LiveData<out Any>> ->
    val data1 = sources[0] as LiveData<Int>
    val data2 = sources[1] as LiveData<String>
    val data3 = sources[2] as LiveData<String>
    // do your work here   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...