2011-07-14 112 views
37

在正常的Scala地圖和flatMap是不同的,flatMap將返回一個迭代的數據展平成一個列表。 但是在Akka文檔中,map和flatMap似乎做了一些不同的事情?在Scala 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() 

可有人請解釋什麼是在阿卡期貨地圖和flatMap這裏有什麼區別?

+0

我認爲這有助於更好地理解它 - 爲什麼我們使用flatMap http://raichoo.blogspot.com/2011/07/from-functions-to-monads-in-scala.html – Phil

回答

59

在 「正常」 斯卡拉(如你所說),地圖和flatMap無關使用列表(查看例如期權)。

Alexey給了你正確的答案。現在,如果你想知道爲什麼我們需要兩者,那麼在編寫期貨時,它允許使用好的for語法。鑑於這樣的:

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

編譯器重寫它:

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

如果按照方法簽名,你應該看到的是,表達式將返回Future[A]類型的東西。

假設現在只能地圖使用,編譯器可以做類似:

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

但是,結果對子級一直Future[Future[A]]類型。這就是爲什麼你需要扁平它。

要了解這個概念的背後,就是一個我讀過的最好的介紹:

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

+7

我沒有意識到扁平化可能會使扁平化的扁平化,我的想法是它將一列對象扁平化爲一個列表。因此,從我的「老」思維中,我認爲它只是走上了名單,並將其攤平。實際上,如同你所說的,未來[未來[A]]類似於列表[列表[A]],平坦化可以使類型變平。一旦我邁出了這一步,我可以更好地理解它。 – Phil

+0

非常感謝!特別是對於帖子!這個「分號」吹了我的腦海! – noru

34

有人能解釋Akka期貨在這裏的地圖和flatMap有什麼區別嗎?

的類型,基本上是:

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

map[A](f: T => A): Future[A] 
+0

確切地說,這有相關性當你有一個方法返回一個未來[A],而不是獲得一個未來[未來[A]]時,你想要未來[A]。 – Mahesh

+0

如果您想了解更多以「地圖」和「flatMap」爲基礎的設計原則,這些原理植根於Monad抽象,我建議由Scala的創建者Martin Odersky的講座https://www.coursera.org/ learn/progfun2/lecture/98tNE/lectures-1-4-monads –

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與實際結果的承諾完成時調用函數。

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

對於一個偉大的文章閱讀:HTTP // danielwestheide.com /博客/ 2013/01/16 /的,新手引導到斯卡拉部分-9-承諾和期貨-IN-實踐。html

相關問題