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 に答える