0

我有点努力让这个结构化。这是我正在尝试做的事情:

def checkResultAndFetchUser(result: WriteResult, encryptedEmail: String): Future[Either[ServiceError, User]] = Future {
  if (result.code contains 11000)
    Left(ServiceError("Email already exists"))
  else if (result.hasErrors)
    Left(ServiceError(result.writeErrors.map(_.errmsg).toString))
  else
    userByEmail(encryptedEmail).map(user =>
      user
    ).recover {
      case NonFatal(ex) => Left(ServiceError(ex.getMessage))
    }
}

checkResultAndFetchUser(
  await(userCollection.insert(encryptedUser)), encryptedUser.email
)

我期望checkResultAndFetchUser返回 a Future[Either[ServiceError, User]],但我看到以下编译器失败:

Error:(155, 28) type mismatch;
 found   : scala.concurrent.Future[Either[DBService.this.ServiceError,com.inland.model.User]]
 required: Either[DBService.this.ServiceError,com.inland.model.User]
Error occurred in an application involving default arguments.
    checkResultAndFetchUser(
                           ^
Error:(150, 19) type mismatch;
 found   : scala.concurrent.Future[Either[DBService.this.ServiceError,com.inland.model.User]]
 required: Either[DBService.this.ServiceError,com.inland.model.User]
        ).recover {
                  ^

userByEmail(encryptedEmail)方法给了我一个Future[Either[ServiceError, User]]我期望的结果,但是为什么以及问题出在哪里?

编辑:我找到了解决方案:

def checkResultAndFetchUser(result: WriteResult, encryptedEmail: String): Future[Either[ServiceError, User]] = {
  if (result.code contains 11000)
    Future(Left(ServiceError("Email already exists")))
  else if (result.hasErrors)
    Future(Left(ServiceError(result.writeErrors.map(_.errmsg).toString)))
  else
    userByEmail(encryptedEmail)
}

await(checkResultAndFetchUser(
  await(userCollection.insert(encryptedUser)), encryptedUser.email
))

可以吗?我的意思是,实现是安全的,因为我使用局部变量来返回一个Future

4

1 回答 1

2

从产生预期结果的意义上说,您的代码是可以的。然而,正如@Łukasz 在评论中提到的那样,这样做有点浪费。

原因是每当您像这样实例化 Future 时,都会产生一个需要在某个 ExecutionContext 上安排的新任务。通常,只要您只需要将已经计算的结果包装在 Future 中(或者如果计算非常快),最好使用Future.successful这样可以避免开销。

以下是我将如何修改 checkResultAndFetchUser 函数:

def checkResultAndFetchUser(result: WriteResult, encryptedEmail: String): Future[Either[ServiceError, User]] = {
  if (result.code contains 11000)
    Future.successful(Left(ServiceError("Email already exists")))
  else if (result.hasErrors)
    Future.successful(Left(ServiceError(result.writeErrors.map(_.errmsg).toString)))
  else
    userByEmail(encryptedEmail)
}
于 2015-10-24T18:45:33.057 回答