带有副作用的平面图

时间:2018-12-25 13:30:35

标签: rx-java rx-java2

我需要基于副作用映射RxJava发射。

每个排放项都将使用以下公式进行映射: f(x) = const * x + counter 当const是偶数时,counter是0;当const是奇数时,counter是-1

每次发射时,计数器都会递增。

常量和发射量都是整数,将从远程资源中获取。

将计数器放置为类属性确实可以解决该问题。但是这样的副作用将使它无法线程安全,并且在重置计数器之前不能被多次调用。

private var counter = 0

fun process(constSource: Single<Int>, entrySource: Flowable<Long>): Flowable<Long> {
  fun mapper(const: Int, entry: Long) = Single.fromCallable {
    if (const % 2 != 0) counter = -1
    const * entry + counter++
  }
  return entrySource
    .withLatestFrom(
      constSource.toFlowable(),
      BiFunction { entry: Long, const: Int -> entry to const }
    )
    .flatMapSingle { (entry, const) -> mapper(const, entry) }
}

@Test
fun `flat map with async side effect`() {
  val constSource = Single.fromCallable { 2 }
  val entrySource = Flowable.fromIterable((1L..5L))

  process(constSource, entrySource)
    .toList()
    .test()
    .await()
    // f = const * entry + counter
    // where counter starts from -1 when const is an odd number
    .assertResult(listOf(2L, 5L, 8L, 11L, 14L))

  process(constSource, entrySource)
    .toList()
    .test()
    .await()
    .assertResult(listOf(2L, 5L, 8L, 11L, 14L)) // will fail
}

这个问题有更好的解决方案吗?

1 个答案:

答案 0 :(得分:0)

虽然您可以在读写此计数时锁定任意对象,但可以采用一种更简单,实用的方法。

天真的解决方案是使用

add_filter( 'bloginfo_url', 'your_callback' )

...假设您正在使用RxKotlin。 (这使lambda变得更简单,我们不必添加SAM conversion。)

,但这将不起作用,因为Observables.combineLatest( Observable.range(0, Int.MAX_VALUE), source ) { index, item -> const * item - (index and 1) } 将OOM,因为它将立即尝试从Observable.range0发出所有值,因此我们只想发出on需求,因此我们可以改用MAX_VALUE,它应该可以正常工作。

Flowable

忽略晦涩的按位运算,为了简洁起见,我在这里添加了它,因为我不知道您的代码是要做什么,或者我将这个返回奇数的Flowables.combineLatest( Flowable.range(0, Int.MAX_VALUE), source.toFlowable(BackPressureStrategy.BUFFER) ) { index, item -> const * item - (index and 1) } 命名为哪种方法,做最可读的事情。