39

在普通的 Scala 中 map 和 flatMap 的不同之处在于 flatMap 将返回一个扁平化到列表中的数据的迭代。但是在 Akka 文档中, map 和 flatMap 似乎做了一些不同的事情?

http://akka.io/docs/akka/1.1/scala/futures.html

它说“通常这工作得很好,因为这意味着运行快速函数的开销很小。如果函数有可能花费大量时间来处理,最好同时完成,为此,我们使用 flatMap:"

val f1 = Future {
  "Hello" + "World"
}

val f2 = f1 flatMap {x =>
  Future(x.length)
}

val result = f2.get()

有人可以解释一下 Akka 期货中的 map 和 flatMap 有什么区别吗?

4

3 回答 3

60

在“普通”Scala(如您所说)中, map 和 flatMap 与 Lists 无关(例如,检查 Option )。

阿列克谢给了你正确的答案。现在,如果您想知道为什么我们需要两者,它允许for在编写期货时使用漂亮的语法。给定类似的东西:

val future3 = for( x <- future1;
                   y <- future2 ) yield ( x + y )

编译器将其重写为:

val future3 = future1.flatMap( x => future2.map( y => x+y ) )

如果您遵循方法签名,您应该会看到表达式将返回 type 的内容Future[A]

假设现在只使用了 map,编译器可能会执行以下操作:

val future3 = future1.map( x => future2.map( y => x+y ) )

但是,结果应该是 type Future[Future[A]]。这就是为什么你需要把它弄平。

要了解背后的概念,这是我读过的最好的介绍之一:

http://www.codecommit.com/blog/ruby/monads-are-not-metaphors

于 2011-07-14T06:52:56.790 回答
35

有人可以解释一下 Akka 期货中的 map 和 flatMap 有什么区别吗?

类型,基本上:

flatMap[A](f: T => Future[A]): Future[A] 

map[A](f: T => A): Future[A] 
于 2011-07-14T06:13:10.053 回答
1

我在这里粘贴这两种方法的实现。英文术语的差异如下 ,并将函数的结果作为新的未来返回

         /** Creates a new future by applying a function to the successful result of
       *  this future. If this future is completed with an exception then the new
       *  future will also contain this exception.
       *
       *  $forComprehensionExamples
       */
      def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { // transform(f, identity)
        val p = Promise[S]()
        onComplete { v => p complete (v map f) }
        p.future
      }

      /** Creates a new future by applying a function to the successful result of
       *  this future, and returns the result of the function as the new future.
       *  If this future is completed with an exception then the new future will
       *  also contain this exception.
       *
       *  $forComprehensionExamples
       */
      def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = {
        import impl.Promise.DefaultPromise
        val p = new DefaultPromise[S]()
        onComplete {
          case f: Failure[_] => p complete f.asInstanceOf[Failure[S]]
          case Success(v) => try f(v) match {
            // If possible, link DefaultPromises to avoid space leaks
            case dp: DefaultPromise[_] => dp.asInstanceOf[DefaultPromise[S]].linkRootOf(p)
            case fut => fut.onComplete(p.complete)(internalExecutor)
          } catch { case NonFatal(t) => p failure t }
        }
    p.future
   }

从实现来看,不同之处在于 flatMap 实际上是在 promise 完成时调用带有结果的函数。

case Success(v) => try f(v) match 

阅读精彩文章:http://danielwestheide.com/blog/2013/01/16/the-neophytes-guide-to-scala-part-9-promises-and-futures-in-practice.html

于 2017-03-24T10:01:13.380 回答