【问题标题】:Scala Future - for comprehension, mix sync and asyncScala Future - 用于理解,混合同步和异步
【发布时间】:2016-08-23 13:46:27
【问题描述】:

在我的method1中,我需要异步调用另一个method2,它返回Option(result1)。比,如果result1为空,我需要异步调用另一个method3,但如果result1不为空,我只需要返回它。

方法如下:

  def signIn(username: String): Future[User] = {
    for {
      foundUser <- userService.findByUsername(username) // this method returns Future[Option[User]], 
      // foundUser is Option[User]
      user <- if (foundUser.isEmpty) {
        val newUser = User(username = "User123")
        userService.create(newUser).map(Some(_)) // this method returns Future[Option[User]]
      }
      else
        // Here I want to return just foundUser, of course, it is not possible. 
        // IS THIS APPROACH CORRECT?? DOES THIS LINE CREATE ASYNCHRONOUS CALL?          
        Future.successful(foundUser)
    } yield user 
  }

问题是:

Future.successful(foundUser) - 这种方法在上面的代码中是否正确?此行是否创建异步调用?如果有,如何避免?我已经异步获取了 foundUser,我不想为了返回已经获取的值而进行额外的异步调用。

【问题讨论】:

    标签: scala future for-comprehension


    【解决方案1】:

    Future.successful 不会在提供的ExecutionContext 上排队附加功能。它只是使用Promise[T] 来创建一个完整的Future[T]

    /** Creates an already completed Future with the specified result.
       *
       *  @tparam T       the type of the value in the future
       *  @param result   the given successful value
       *  @return         the newly created `Future` instance
       */
      def successful[T](result: T): Future[T] = Promise.successful(result).future
    

    附带说明,您可以使用Option.fold 减少样板文件的数量:

    def signIn(username: String): Future[User] = 
      userService
        .findByUsername(username)
        .flatMap(_.fold(userService.create(User(username = "User123")))(Future.successful(_))
    

    【讨论】:

    • 顺便说一句,如果我写Future { foundUser}而不是Future.successful(foundUser),它是异步执行的,对吧?
    • @moreo 是的,会导致ExecutionContext上的函数排队。
    【解决方案2】:

    @Yuval Itzchakov 回答了您的问题,但作为旁注,您可能希望在您的情况下直接使用 flatMap 和模式匹配。我个人觉得它更具可读性:

    def signIn(username: String): Future[User] =
      userService.findByUsername(username)
        .flatMap {
          case Some(user) => Future.successful(user)
          case _ => userService.create(User(username = "User123"))
        }
    

    【讨论】:

    • 谢谢,我先用 flatMap 实现了它,但是我这里的例子与我原来的方法相比非常简化,我有很多嵌套的 flatMaps/maps,这就是我决定重写的原因它与理解
    猜你喜欢
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多