简体   繁体   English

在Scala中处理future [Ething]类型

[英]Dealing with Future[Either] Types in Scala

I'm a bit struggling to get this structured. 我有点难以使它结构化。 Here is what I'm trying to do: 这是我想要做的:

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
)

I'm expecting that the checkResultAndFetchUser returns a Future[Either[ServiceError, User]] , but I get to see the following compiler failures: 我期望checkResultAndFetchUser返回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 {
                  ^

The userByEmail(encryptedEmail) method gives me a Future[Either[ServiceError, User]] as I would expect it to, but why and where is the problem? 正如我所期望的那样, userByEmail(encryptedEmail)方法为我提供了Future[Either[ServiceError, User]] ,但问题出在哪里?

EDIT: I've found a solution: 编辑:我找到了一个解决方案:

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
))

Is that Okay? 这样可以吗? I mean, the implementation is safe as I'm using local variables to return a Future ! 我的意思是,实现是安全的,因为我正在使用局部变量返回Future

Your code is ok in the sense that it produce the expected result. 就可以产生预期结果的意义而言,您的代码是可以的。 However as @Łukasz mentioned in the comment, doing it this way is a little bit wasteful. 但是,正如@Łukasz在评论中提到的那样,这样做有点浪费。

The reason is that whenever you instantiate a Future like that, a new task is spawned that needs to be scheduled on some ExecutionContext. 原因是,每当您这样实例化Future时,都会产生一个新任务,该任务需要在某个ExecutionContext上进行调度。 Usually whenever you just need to wrap an already computed result in a Future (or if the computation is really quick) is better to use Future.successful so to avoid overhead. 通常,每当您只需要将已计算的结果包装在Future中时(或者如果计算速度非常快),最好使用Future.successful以避免开销。

Here's how I would modify the checkResultAndFetchUser function: 这是我修改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)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM