【问题标题】:how to return either value or throw error in Scala如何在Scala中返回值或抛出错误
【发布时间】:2019-03-07 23:12:26
【问题描述】:

我有一个电子邮件列表,对于每一个,我都会在电子邮件表中查找它以查看该电子邮件是否存在。如果是这样,什么也不做,我会抛出错误。这是我的代码;

def lookupEmailStatus(email: EmailAddress, requestId: RequestId)(
      implicit ec: ExecutionContext): HttpServiceResult[List[EmailStatusDTO]] = {
    emailDatabase
      .getEmailStatusByEmail(email, requestId)
      .map(
        l =>
        if (l.isEmpty) {
          logger.error(
            LoggingMessage(
              requestId,
              s"Email status not found by ${email.email} failed"))
          EntityNotFound(s"${email.email}", requestId)
        } else {
          l
        }
      )
      .leftMap[HttpError] {
        case e =>
          logger.error(
            LoggingMessage(
              requestId,
              s"Retrieve email status by ${email.email} failed"))
          DatabaseError(e.message, requestId)
      }
  }

当我运行代码时出现错误:

Error:(57, 27) type mismatch;
 found   : cats.data.EitherT[model.HttpError,Product with Serializable]
 required: model.HttpServiceResult[List[EmailStatusDTO]]
    (which expands to)  cats.data.EitherT[model.HttpError,List[EmailStatusDTO]]
      .leftMap[HttpError] {

如果我删除了 .map(..) 方法,它会正常工作,但这不是我想要的:

def lookupEmailStatus(email: EmailAddress, requestId: RequestId)(
          implicit ec: ExecutionContext): HttpServiceResult[List[EmailStatusDTO]] = {
        emailDatabase
          .getEmailStatusByEmail(email, requestId)
          .leftMap[HttpError] {
            case e =>
              logger.error(
                LoggingMessage(
                  requestId,
                  s"Retrieve email status by ${email.email} failed"))
              DatabaseError(e.message, requestId)
          }
      }

这里是类型定义:

type HttpServiceResult[A] = ServiceResult[HttpError, A]
type ServiceResult[Err, A] = EitherT[Future, Err, A]

【问题讨论】:

    标签: scala scala-cats


    【解决方案1】:

    如果if 的一个分支返回一个列表,而另一个分支返回一个错误,那么if 完全返回Product with Serializable

    尝试将map 替换为flatMap 并将分支结果包装为EitherT

    def lookupEmailStatus(email: EmailAddress, requestId: RequestId)(
        implicit ec: ExecutionContext): HttpServiceResult[List[EmailStatusDTO]] = 
        emailDatabase
          .getEmailStatusByEmail(email, requestId)
          .leftMap[HttpError] {
            case e =>
              logger.error(
                LoggingMessage(
                  requestId,
                  s"Retrieve email status by ${email.email} failed"))
              DatabaseError(e.message, requestId)
          }.flatMap[HttpError, List[EmailStatusDTO]](
            /*(*/l/*: List[EmailStatusDTO])*/ =>
              if (l.isEmpty) {
                logger.error(
                  LoggingMessage(
                    requestId,
                    s"Email status not found by ${email.email} failed"))
                EitherT.leftT/*[Future, List[EmailStatusDTO]]*/(EntityNotFound(s"${email.email}", requestId))
              } else {
                EitherT.rightT/*[Future, HttpError]*/(l)
              }
          )
    

    【讨论】:

      【解决方案2】:

      正如@dmytro-mitin 已经提到的,问题的根本原因是您在条件的两个分支中没有返回相同的类型。解决此问题的一种方法是确保您返回正确的类型。

      另一种我认为更好的方法是使用cats.data.EitherT.ensure 进行list.isEmpty 检查。这样你就可以明确你关心的内容(即如果列表为空,则返回错误)并且不必手动处理快乐的情况。

      您的代码将变为:

      def lookupEmailStatus(email: EmailAddress, requestId: RequestId)(
            implicit ec: ExecutionContext): HttpServiceResult[List[EmailStatusDTO]] = {
          emailDatabase
            .getEmailStatusByEmail(email, requestId)
            .ensure({
               logger.error(LoggingMessage(requestId, s"Email status not found by ${email.email} failed"))}
               EntityNotFound(s"${email.email}", requestId)
            })(!_.isEmpty)
            .leftMap[HttpError] {
              case e =>
                logger.error(
                  LoggingMessage(
                    requestId,
                    s"Retrieve email status by ${email.email} failed"))
                DatabaseError(e.message, requestId)
            }
        }
      

      【讨论】:

      • leftMap 应该在 ensure 之前。否则EntityNotFound 将被DatabaseError 吞噬。或者你可以匹配leftMap
      • 感谢您的提示,让我感到困惑的一件事是,如果他们有 leftmap,为什么他们不能也有 rightMap,以便我可以执行以下操作:emailDatabase.getEmailStatusByEmail(email, reuqestId) .leftMap[HttpError]{...logging + DatabaseError...}.rightMap{ l=> if (l.isEmpty) E.left(EntityNotFound)}
      猜你喜欢
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      • 2018-04-23
      • 2021-07-29
      • 2017-06-01
      • 2021-05-30
      • 2014-08-22
      相关资源
      最近更新 更多