如何在Scala中返回值或引发错误

时间:2019-03-07 06:18:43

标签: scala scala-cats

我有一封电子邮件列表,对于每封电子邮件,我都会在电子邮件表中查找该电子邮件,以查看该电子邮件是否存在。如果是这样,别无选择,我会抛出错误。这是我的代码;

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]

2 个答案:

答案 0 :(得分:4)

如果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)
          }
      )

答案 1 :(得分:1)

正如@ 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)
      }
  }