获取流的收集中的当前和先前值

Vla*_*yar 10 coroutine kotlin kotlin-coroutines coroutinescope kotlin-flow

我需要处理流收集中的当前值和先前值,因此我需要一些具有如下作用的运算符:

----A----------B-------C-----|--->

---(null+A)---(A+B)---(B+C)--|--->
Run Code Online (Sandbox Code Playgroud)

一个想法是这样的:

fun <T: Any> Flow<T>.withPrevious(): Flow<Pair<T?, T>> = flow {
    var prev: T? = null
    this@withPrevious.collect {
        emit(prev to it)
        prev = it
    }
}
Run Code Online (Sandbox Code Playgroud)

但这样就无法控制执行第一个流程的上下文。有没有更灵活的解决方案?

m.r*_*ter 13

有一个运算符可以使这变得非常简单:runningFold

该文档有一个关于如何使用它来收集流的每次发射的示例;这可以很容易地适应我们的需求

data class History<T>(val previous: T?, val current: T)

// emits null, History(null,1), History(1,2)...
fun <T> Flow<T>.runningHistory(): Flow<History<T>?> =
    runningFold(
        initial = null as (History<T>?),
        operation = { accumulator, new -> History(accumulator?.current, new) }
    )

// doesn't emit until first value History(null,1), History(1,2)...
fun <T> Flow<T>.runningHistoryAlternative(): Flow<History<T>> =
    runningHistory().filterNotNull()
Run Code Online (Sandbox Code Playgroud)

您可能需要调整可空性以适合您的用例


Ser*_*gey 4

Flows 是连续的,因此您可以使用变量来存储先前的值:

coroutineScope.launch {
    var prevValue = null
    flow.collect { newValue ->
        // use prevValue and newValue here
        ...
        // update prevValue
        prevValue = newValue
    }
}
Run Code Online (Sandbox Code Playgroud)