在 Scala 中处理闭包和期货

Dealing with Closures and Futures in Scala

我有以下方法对 Futures 进行一些处理:

def registerNewUser(user: User): Future[Either[ServiceError, User]] = async {
  val encryptedUser =
    user.copy(encrypt(user))

  def checkResultAndFetchUser(result: WriteResult, encryptedEmail: String): Future[Either[ServiceError, User]] = {
    if (result.hasErrors)
      Future.successful(Left(ServiceError(result.writeErrors.map(_.errmsg).toString)))
    else
      userByEmail(encryptedEmail)
  }

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

  val result = userCollection.insert(encryptedUser).map( writeRes =>
    checkResultAndFetchUser(writeRes, encryptedUser.email)
  ).recover {
    case res: WriteResult => Future.successful(handleInsertError(res))
  }

  await(result.flatMap(fut => fut))
}

这是我的问题:

  1. checkResultAndFetchUser方法中使用了encryptedUser局部变量,userCollection.insert(encryptedUser)returns一个Future,也是有没有可能在 checkResultAndFetchUser 方法中捕获另一个 encryptedUser?那就意味着,我在劫难逃!

  2. 这是处理 Future 及其处理的好方法吗?

我不太确定你的第一个问题是什么意思,但只有一个 encryptedUser 值,所以即使两个函数 return 和 Future 它们都使用同样的 encryptedUser.

为了处理你 Futures :

  • 您并没有真正使用 async / await,因为您只在 "result" Future.
  • 上使用 await
  • 你在userCollection.insert()上使用map,然后使用result.flatMap(fut => fut),可以简化为直接使用flatMap

    userCollection.insert(encryptedUser).flatMap( writeRes =>
      checkResultAndFetchUser(writeRes, encryptedUser.email)
    )
    
  • 也可以写成for comprehension

最终结果可能如下所示:

def registerNewUser(user: User): Future[Either[ServiceError, User]] = { 
  def checkResultAndFetchUser(result: WriteResult, encryptedEmail: String) = ???

  def handleInsertError(result: WriteResult) = ???

  def insertUser(user: User): WriteResult =
    userCollection.insert(user).recover {
      case res: WriteResult => handleInsertError(res)
    }

  val encryptedUser = user.copy(encrypt(user))

  for {
    writeRes <- insertUser(encryptedUser)
    user     <- checkResultAndFetchUser(writeRes, encryptedUser.email)
  } yield user
}