链式 kotlin 流程取决于结果状态
Chain kotlin flows depends on Result state
我正在寻找最“干净”的方式来实现以下逻辑:
- 我有N个方法,大家returns Flow
>(类型不同)
- 我想链接这些方法,所以如果 1 returns Result.Success,然后调用 2nd 等等。
最明显的方法是:
methodA().map { methodAResult ->
when (methodAResult) {
is Result.Success -> {
methodB(methodAResult).map { methodBResult ->
when (methodBResult) {
is Result.Success -> {
methodC(methodAResult).map { methodCResult ->
when (methodCResult) {
is Result.Success -> TODO()
is Result.Failure -> TODO()
}
}
}
is Result.Failure -> TODO()
}
}
}
is Result.Failure -> TODO()
}
}
但它看起来像一个众所周知的“回调地狱”。你有什么办法可以避免吗?
我相信在这个用例中,您应该使用 suspend
函数并 compose 使用 await()
函数。
错误应按照 here.
中所述通过异常传递
我相信这可以用 transform operator:
methodA().transform { methodAResult ->
when (methodAResult) {
is Success -> methodB(methodAResult).collect { emit(it) }
is Failure -> TODO()
}
}.transform { methodBResult ->
when (methodBResult) {
is Success -> methodC(methodBResult).collect { emit(it) }
is Failure -> TODO()
}
}.transform { methodCResult ->
when (methodCResult) {
is Success -> TODO()
is Failure -> TODO()
}
}
对Михаил Нафталь提供的解决方案稍作修改
methodA()
.flatMapMerge {
when (it) {
is Result.Success -> methodB(it)
is Result.Failure -> emptyFlow()
}
}.flatMapMerge {
when (it) {
is Result.Success -> methodC(it)
is Result.Failure -> emptyFlow()
}
}.collect {
when (it) {
is Result.Success -> TODO()
is Result.Failure -> TODO()
}
}
将一个流的输出合并到另一个流是 flatMap 的目标,因此使用 flatMap 似乎更简洁一些。
如果此结果 class 具有 map
、fold
或 getOrNull
类型的方法,则可以进一步清理并删除 when 块.
此外,如果您需要传播要收集的故障,则可以将对 emptyFlow 的调用替换为仅输出所需故障的流。
很遗憾 flatMap
方法仍然不存在。
但是你可以使用 mapCatching
:
methodA
.mapCatching { a -> methodB(a).getOrThrow() }
.mapCatching { b -> methodC(b).getOrThrow() }
或者制作您自己的 flatMap
扩展函数:
fun <T, R> Result<T>.flatMap(block: (T) -> (Result<R>)): Result<R> {
return this.mapCatching {
block(it).getOrThrow()
}
}
methodA
.flatMap { a -> methodB(a) }
.flatMap { b -> methodC(b) }
我正在寻找最“干净”的方式来实现以下逻辑:
- 我有N个方法,大家returns Flow
>(类型不同) - 我想链接这些方法,所以如果 1 returns Result.Success,然后调用 2nd 等等。
最明显的方法是:
methodA().map { methodAResult ->
when (methodAResult) {
is Result.Success -> {
methodB(methodAResult).map { methodBResult ->
when (methodBResult) {
is Result.Success -> {
methodC(methodAResult).map { methodCResult ->
when (methodCResult) {
is Result.Success -> TODO()
is Result.Failure -> TODO()
}
}
}
is Result.Failure -> TODO()
}
}
}
is Result.Failure -> TODO()
}
}
但它看起来像一个众所周知的“回调地狱”。你有什么办法可以避免吗?
我相信在这个用例中,您应该使用 suspend
函数并 compose 使用 await()
函数。
错误应按照 here.
我相信这可以用 transform operator:
methodA().transform { methodAResult ->
when (methodAResult) {
is Success -> methodB(methodAResult).collect { emit(it) }
is Failure -> TODO()
}
}.transform { methodBResult ->
when (methodBResult) {
is Success -> methodC(methodBResult).collect { emit(it) }
is Failure -> TODO()
}
}.transform { methodCResult ->
when (methodCResult) {
is Success -> TODO()
is Failure -> TODO()
}
}
对Михаил Нафталь提供的解决方案稍作修改
methodA()
.flatMapMerge {
when (it) {
is Result.Success -> methodB(it)
is Result.Failure -> emptyFlow()
}
}.flatMapMerge {
when (it) {
is Result.Success -> methodC(it)
is Result.Failure -> emptyFlow()
}
}.collect {
when (it) {
is Result.Success -> TODO()
is Result.Failure -> TODO()
}
}
将一个流的输出合并到另一个流是 flatMap 的目标,因此使用 flatMap 似乎更简洁一些。
如果此结果 class 具有 map
、fold
或 getOrNull
类型的方法,则可以进一步清理并删除 when 块.
此外,如果您需要传播要收集的故障,则可以将对 emptyFlow 的调用替换为仅输出所需故障的流。
很遗憾 flatMap
方法仍然不存在。
但是你可以使用 mapCatching
:
methodA
.mapCatching { a -> methodB(a).getOrThrow() }
.mapCatching { b -> methodC(b).getOrThrow() }
或者制作您自己的 flatMap
扩展函数:
fun <T, R> Result<T>.flatMap(block: (T) -> (Result<R>)): Result<R> {
return this.mapCatching {
block(it).getOrThrow()
}
}
methodA
.flatMap { a -> methodB(a) }
.flatMap { b -> methodC(b) }