Реактор: как получить плоский кортеж после использования zipWhen с другим кортежем?

#kotlin #reactive-programming #project-reactor

#kotlin #реактивное программирование #проект-реактор

Вопрос:

Когда я связываю несколько zipWhen вызовов, результатом будет a Tuble2<Tuple2<Foo, Bar>, Bam> вместо a Tuple3<Foo, Bar, Bam> . Это становится хуже с каждым последующим zipWhen .

Пример:

 val getFoo()
  .zipWhen { foo ->
    getBar(foo)
  }
  .zipWhen { fooBar -> 
    getBam(fooBar.t1, fooBar.t2)
  }
  .doOnNext { fooBarBam ->
    log.debug { "foo: ${fooBarBam.t1.t1}" }
    log.debug { "bar: ${fooBarBam.t1.t2}" }
    log.debug { "bam: ${fooBarBam.t2}" }
  }
  

Какой самый элегантный и многоразовый способ получить Tubple3 в doOnNext?

Ответ №1:

Что вы можете сделать, так это использовать zipWhen с комбинатором типа:

 getFoo()
.zipWhen {foo -> getBar(foo) }
.zipWhen({ t -> getBam(t.t1, t.t2) }, {a, b -> Tuples.of(a.t1, a.t2, b)})
.doOnNext { fooBarBam ->
   log.debug { "foo: ${fooBarBam.t1}" }
   log.debug { "bar: ${fooBarBam.t2}" }
   log.debug { "bam: ${fooBarBam.t3}" }
}
  

Ответ №2:

Полезные утилиты:

 fun <T1, T2, T3, T4, T5, U> flat(t: Tuple5<T1, T2, T3, T4, T5>, u: U): Tuple6<T1, T2, T3, T4, T5, U> = Tuples.of(t.t1, t.t2, t.t3, t.t4, t.t5, u)
fun <U, T1, T2, T3, T4, T5> flat(u: U, t: Tuple5<T1, T2, T3, T4, T5>): Tuple6<U, T1, T2, T3, T4, T5> = Tuples.of(u, t.t1, t.t2, t.t3, t.t4, t.t5)
fun <T1, T2, T3, T4, U> flat(t: Tuple4<T1, T2, T3, T4>, u: U): Tuple5<T1, T2, T3, T4, U> = Tuples.of(t.t1, t.t2, t.t3, t.t4, u)
fun <U, T1, T2, T3, T4> flat(u: U, t: Tuple4<T1, T2, T3, T4>): Tuple5<U, T1, T2, T3, T4> = Tuples.of(u, t.t1, t.t2, t.t3, t.t4)
fun <T1, T2, T3, U> flat(t: Tuple3<T1, T2, T3>, u: U): Tuple4<T1, T2, T3, U> = Tuples.of(t.t1, t.t2, t.t3, u)
fun <U, T1, T2, T3> flat(u: U, t: Tuple3<T1, T2, T3>): Tuple4<U, T1, T2, T3> = Tuples.of(u, t.t1, t.t2, t.t3)
fun <T1, T2, U> flat(t: Tuple2<T1, T2>, u: U): Tuple3<T1, T2, U> = Tuples.of(t.t1, t.t2, u)
fun <U, T1, T2> flat(u: U, t: Tuple2<T1, T2>): Tuple3<U, T1, T2> = Tuples.of(u, t.t1, t.t2)
  

Использование:

 import reactor.kotlin.core.util.function.*

    fun doStuff(id:Long){
        getProduct(id)
            .zipWith(Mono.just("a string"))
            .zipWith(Mono.just(42),
                { t, u -> flat(t, u) })
            .zipWith(Mono.just("anotherstring"),
                { t, u -> flat(t, u) })
            .doOnNext { (product, aString, number, anotherString) ->
                log.debug(product.description   " "   aString   " "   number   " "   anotherString)
            }
    }
  

Импорт заключается в деструктурировании полученного кортежа.

Ответ №3:

Самый очевидный способ, которым я хочу выставить себя на голосование:

   .map {
    Tuples.of(it.t1.t1, it.t1.t2, it.t2)
  }
  

и извлечение функции.

 fun <T1, T2, T3> flatTuple(t: Tuple2<Tuple2<T1, T2>, T3>): Tuple3<T1, T2, T3> =
    Tuples.of(t.t1.t1, t.t1.t2, t.t2)

// ...

  .map { flatTuple(it) }