【问题标题】:Dependent futures依赖期货
【发布时间】:2015-08-06 01:56:26
【问题描述】:

开始使用 Scala 期货,我被依赖期货卡住了。

让我们举个例子。我搜索地点并获得Future[Seq[Place]]。对于这些地方中的每一个,我都会搜索最近的地铁站(服务会返回Future[List[Station]])。

我会这样写:

Place.get()
.map { places =>
    places.map { place =>
        Station.closestFrom(place).map { stations =>
            SearchResult(place, stations)
        }
    }
}

那件事会让我得到一个Future[Seq[Future[SearchResult]]]... 这...不是我所期望的。

为了获得Future[Seq[SearchResult]],我错过了什么?

谢谢大家,

阿尔班

【问题讨论】:

    标签: scala playframework-2.0 future


    【解决方案1】:

    您的解决方案中缺少两个 Future 概念:flatMapFuture.sequence

    解释每个:

    flatMap 就像map 一样,除了给它一个来自future.map(A => B) 的函数,而是给它一个来自future.flatMap(A => Future[B]) 的函数。这样您就可以将 Future 链接在一起。

    Future.sequence 是一个辅助函数,它将期货列表与列表的未来结合起来:Seq[Future[A]] => Future[Seq[A]]

    使用Future API 的这两个功能,我们可以将您的答案更改为:

    Place.get().flatMap { places =>
        Future.sequence(places.map { place =>
            Station.closestFrom(place).map { stations =>
                SearchResult(place, stations)
            }
        })
    }
    

    【讨论】:

      【解决方案2】:

      短版

      使用 for-comprehension 通常比直接使用 map/flatMap 更容易使用期货。在您的情况下,它应该如下所示:

      for {places        <- Place.get()
           searchResults <- Future.traverse(places)(place => for (stations <- Station.closestFrom(place))
                                                             yield SearchResult(place,stations)
                                                    )
      } yield searchResults
      

      详细版

      Future 是一个 monad,它为您提供了几种链接操作的方法。

      • 如果您想将“常规”函数f : A =&gt; B 应用于myfuture : Future[A] 框内的内容,实际上map 是获得Future[B] 的方法。但在目前的情况下,Station.closestFrom 不是给你List[Stattion],而是Future[List[Station]]
      • 如果你想应用一个单子操作h : A =&gt; Future[B] 或链接其中的几个(这里是Places.getStation.closestFrom),flatMap 是要走的路。将h 应用到Future[A] 会得到Future[B]
      • 如果您想将一元操作h : A =&gt; Future[B] 应用于places : Seq[A] 之类的集合,则应使用Future.traverse : Seq[A] =&gt; (A =&gt; Future[B]) =&gt; Future[Seq[B]]

      此外,Scala 的 for-compresention 只是 flatMap/map 的语法糖,因此您可以使用简洁明了的 for 循环,而不是直接使用这些代码编写复杂的代码。循环:

      for { variable1 <- f1
            variable2 <- f2
      } yield expression
      

      相当于(没有优化):

      f1.flatMap( variable1 => f2.map(variable2 => expression))
      

      不要犹豫,使用理解,它真的很有帮助。

      【讨论】:

      • 不错!但是您的示例似乎没有“按原样”编译。 place 变量未定义......我说的对吗?但它很快就可以在两行之间添加place &lt;- places
      • 确实如此。抱歉,这次新版本应该没问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-24
      • 2013-10-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多