我正在try 设置一些数据,然后调用服务.每一步都可能失败,所以我try 使用Arrow's来管理这一点.

但我最终得到了很多嵌套平面图.

下面的代码片段说明了我要做的事情:

import arrow.core.Either
import arrow.core.flatMap

typealias ErrorResponse = String
typealias SuccessResponse = String

data class Foo(val userId: Int, val orderId: Int, val otherField: String)
data class User(val userId: Int, val username: String)
data class Order(val orderId: Int, val otherField: String)

interface MyService {
    fun doSomething(foo: Foo, user: User, order: Order): Either<ErrorResponse, SuccessResponse> {
        return Either.Right("ok")
    }
}

fun parseJson(raw: String): Either<ErrorResponse, Foo> = TODO()
fun lookupUser(userId: Int): Either<ErrorResponse, User> = TODO()
fun lookupOrder(orderId: Int): Either<ErrorResponse, Order> = TODO()

fun start(rawData: String, myService: MyService): Either<ErrorResponse, SuccessResponse> {
    val foo = parseJson(rawData)
    val user = foo.flatMap {
        lookupUser(it.userId)
    }
    //I want to lookupOrder only when foo and lookupUser are successful
    val order = user.flatMap {
        foo.flatMap { lookupOrder(it.orderId) }
    }
    //Only when all 3 are successful, call the service
    return foo.flatMap { f ->
        user.flatMap { u ->
            order.flatMap { o ->
                myService.doSomething(f, u, o)
            }
        }
    }
}

我相信有更好的方法.有人能帮我一个惯用的方法吗?

推荐答案

您可以使用either { } DSL,它可以通过either.eager { } builder以suspend方式或non-suspend方式提供.

这样你就可以使用suspend fun <E, A> Either<E, A>.bind(): A.

重写代码示例:

fun start(rawData: String, myService: MyService): Either<ErrorResponse, SuccessResponse> =
  either.eager {
    val foo = parseJson(rawData).bind()
    val user =  lookupUser(foo.userId).bind()
    val order = lookupOrder(foo.orderId).bind()
    myService.doSomething(foo, user, order).bind()
  }

如果遇到Either.Left,则bind()将返回either.eager块,并返回遇到的Either.Left值.

Kotlin相关问答推荐

在Kotlin中将ClosedRange字符串转换为List?<>

我可以检测一个函数是否在Kotlin中被递归调用(即,重入)吗?

Jetpack Compose Material3和Material2 Slider onValueChangeFinded()的行为不同

为什么在Spring中,对事务性方法调用的非事务方法调用仍然在事务中运行?

插入/更新/upsert时不发出房间流

如何编写带有依赖项的自定义Kotlin串行化程序?

如何避免使用公共类实现内部接口

Webpack 配置未应用于 kotlin 多平台react 项目

区分函数和扩展

使用 Discord4j 交叉发布 Discord 消息

Kotlin - 当表达式返回函数类型

在粘贴时将 java 转换为 kotlin

如何从定义它们的类外部调用扩展方法?

在 Scaffold Jetpack Compose 内的特定屏幕上隐藏顶部和底部导航器

在 Kotlin 中取最后 n 个元素

@uncheckedVariance 在 Kotlin 中?

launch 仅从 Kotlin 1.3 开始可用,不能在 Kotlin 1.2 中使用

Firestore - 如何在 Kotlin 中排除数据类对象的字段

在 Kotlin 中创建非绑定服务

Kotlin Coroutines:等待多个线程完成