You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Doobie与Cats-Effect实现错误处理及代码类型错误修复

问题解决:Cats-Effect + Doobie 错误处理类型不匹配

错误原因拆解

你的代码有三个核心问题:

  1. 画蛇添足用Sync[F].delay包裹了query.transact——transact本身就返回F类型的结果,不需要再用delay包装,反而把上下文搞混了
  2. flatMap里直接返回Right/Left纯值,但flatMap要求返回F[B]类型的结果,纯Either值不符合要求
  3. 直接用println是未封装的副作用,违反了Cats-Effect的纯函数原则

修正后的代码

override def getUser(uuid: UUID): F[Either[String, User]] = {
  val query = sql"""SELECT email, password FROM "user" WHERE "userId" = $uuid"""
    .query[User]
    .option

  query.transact(transactor).attempt.flatMap {
    case Right(Some(user)) => Sync[F].pure(Right(user))
    case Right(None) => Sync[F].pure(Left("User not found"))
    case Left(error) =>
      Sync[F].delay(println(s"Error occurred during getUser query: $error")) *>
      Sync[F].pure(Left("Something went wrong while fetching user details"))
  }
}

优化:用自定义错误类型替代String(类型更安全)

推荐定义专用的错误类型,避免用模糊的String传递错误:

// 先定义自定义错误类型
sealed trait UserError
case object UserNotFound extends UserError
case class DatabaseError(msg: String, cause: Throwable) extends UserError

// 修正后的getUser方法
override def getUser(uuid: UUID): F[Either[UserError, User]] = {
  val query = sql"""SELECT email, password FROM "user" WHERE "userId" = $uuid"""
    .query[User]
    .option

  query.transact(transactor).attempt.flatMap {
    case Right(Some(user)) => Sync[F].pure(Right(user))
    case Right(None) => Sync[F].pure(Left(UserNotFound))
    case Left(error) =>
      Sync[F].delay(println(s"Error occurred during getUser query: $error")) *>
      Sync[F].pure(Left(DatabaseError("Failed to fetch user", error)))
  }
}

关键修正点说明

  • 去掉多余的Sync[F].delay,直接使用query.transact返回的F上下文
  • 用Sync[F].pure把纯Either值包装成F类型,满足flatMap的返回要求
  • 用Sync[F].delay包裹println,把副作用封装到F上下文中
  • (可选)用自定义错误类型替代String,让错误处理更类型安全,便于后续匹配处理

内容的提问来源于stack exchange,提问作者Vaibhav Pandey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:23:17