3

我正在我当前的 Android 应用程序中调查 Kotlin Coroutines & Channels。

我有以下代码来管理远程 Api 调用和控制 UI 副作用

   private val historical: CompletableDeferred<List<Any>> = CompletableDeferred()
   private val mutex = Mutex()

    @ExperimentalCoroutinesApi
    fun perform(action: Action): ReceiveChannel<List<Any>> =
        produce {

          mutex.withLock {
            if (historical.isCompleted) {
                send(historical.getCompleted())
                return@produce
            }  

            send(action.sideEffects)
            val networkResponse = repository.perform(action)
            send(networkResponse.sideEffects)
            send(listOf(networkResponse)).also {
                    historical.complete(listOf(response))
                }
            }
        }

上面的代码给了我想要的结果,但是我想将它重构为类似于函数式编程“铁路模式”的东西https://android.jlelse.eu/real-world-functional-programming-with-kotlin-arrow- b5a98e72f5e3

我的流程在哪里

stepOne(Historical.completed)
.stepTwo(action.sideEffects)
.stepThree(getReaction())
.stepFour(reaction.sideEffects)
.finalStep(reaction)

这将在任何步骤失败或历史“已完成”时“短路”

是否有可能在 Kotlin 中实现这种调用方式?和/或 Kotlin & Arrow.kt?

4

1 回答 1

3

您可以使用 Arrow-kt 的Either

您可以使用Either's mapLeft(), map(), flatMap().

如果结果是Exceptionuse mapLeft()。结果中的返回值mapLeft()将是新LeftEither,例如返回是String,结果是Either<String, List<Any>>。如果结果是Right,即List<Any>mapLeft()将被跳过,但结果类型无论如何都会改变,因此您将拥有Either<String, List<Any>>值为 的类型Right<List<Any>>。如果您选择这样,您也可以返回相同ExceptionmapLeft()

如果你不需要处理特定的错误,你可以链接map()flatMap(). map()基本上是 mapRight() 并且flatMap()当您想要链接调用时很有用,即在链中的某个地方有一个接收器List<Any>可能会失败,并且您想以Exception相同的方式处理Either该调用,您可以返回 new EitherfromflatMap()

代码看起来像这样

fun perform(action: Either<Exception, Action>): ReceiveChannel<List<Any>> =
    produce {
        // if action is always right, you can start it as Right(action) but then first mapLeft does not make any sense
        if (historical.completed) action
            .mapLeft {
                // handle actions exception here
                // transform it to something else or just return it
                send(action.sideEffects)
                it
            }.flatMap {
                // handle right side of action either
                // assume here that repository may fail and returns Either<Exception, NetworkResponse>
                repository.perform(it)
            }.mapLeft {
                // handle repositorys exception here
                // transform it to something else or just return it
                send(it)
                it
            }.map {
                // handle network response
                send(listOf(networkResponse))
                historical.complete(listOf(networkResponse))
            }
    }
于 2019-11-29T09:09:24.663 回答