基于Doobie与Cats-Effect实现错误处理及代码类型错误修复
问题解决:Cats-Effect + Doobie 错误处理类型不匹配
错误原因拆解
你的代码有三个核心问题:
- 画蛇添足用
Sync[F].delay包裹了query.transact——transact本身就返回F类型的结果,不需要再用delay包装,反而把上下文搞混了 flatMap里直接返回Right/Left纯值,但flatMap要求返回F[B]类型的结果,纯Either值不符合要求- 直接用
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
相关产品推荐
相关产品推荐

