如何 return 在 Scala 中赋值或抛出错误
how to return either value or throw error in Scala
我有一个电子邮件列表,对于每个电子邮件,我都会在电子邮件 table 中查找它以查看该电子邮件是否存在。如果是这样,什么都不做我会抛出错误。这是我的代码;
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]
如果 if
returns 一个列表的一个分支和其他 returns 一个错误,则完全 if
returns Product with Serializable
.
尝试用 flatMap
替换 map
并用 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)
}
)
正如@dmytro-mitin 已经提到的,问题的根本原因是您在条件的两个分支中没有 returning 相同的类型。解决此问题的一种方法是确保您 return 使用正确的类型。
另一种在我看来更好的方法是使用 cats.data.EitherT.ensure
进行 list.isEmpty
检查。这样你就可以明确你关心的事情(即如果列表为空,return 错误)并且不必手动处理满意的情况。
您的代码将变为:
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)
}
}
我有一个电子邮件列表,对于每个电子邮件,我都会在电子邮件 table 中查找它以查看该电子邮件是否存在。如果是这样,什么都不做我会抛出错误。这是我的代码;
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]
如果 if
returns 一个列表的一个分支和其他 returns 一个错误,则完全 if
returns Product with Serializable
.
尝试用 flatMap
替换 map
并用 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)
}
)
正如@dmytro-mitin 已经提到的,问题的根本原因是您在条件的两个分支中没有 returning 相同的类型。解决此问题的一种方法是确保您 return 使用正确的类型。
另一种在我看来更好的方法是使用 cats.data.EitherT.ensure
进行 list.isEmpty
检查。这样你就可以明确你关心的事情(即如果列表为空,return 错误)并且不必手动处理满意的情况。
您的代码将变为:
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)
}
}