2017-02-20 32 views
0

У меня есть служба HTTP Akka, который возвращает строку, как показано ниже:Почему моя карта() не работает?

val route1: Route = { 
    path("hello") { 
     get{ 
     complete{ 
      println("Inside r1") 
      "You just accessed hello" 
     } 
     } 
    } 
} 

Я пытаюсь понять разницу между картой и flatMap

Например, приведенный ниже код дает мне результат, Ожидаемый результат:

val future1: Future[String] = 
    Http() 
    .singleRequest(
     HttpRequest(method = HttpMethods.GET, 
        uri = "http://localhost:8187/hello")) 
    .flatMap(testFlatFunc) 

def testFlatFunc(x: HttpResponse): Future[String] = { 
    Unmarshal(x).to[String] 
} 

Но, если я пытаюсь заменить его на карте, как показано ниже я получаю выход как FulfilledFuture(You just accessed hello)

val future1: Future[String] = Http() 
    .singleRequest(
     HttpRequest(method = HttpMethods.GET, 
        uri = "http://localhost:8187/hello")) 
    .map(testFunc) 

def testFunc(x: HttpResponse): String={ 
    Unmarshal(x).to[String].toString 
} 

Почему моя карта() не работает должным образом?

ответ

1

Это о том, что вы делаете в testFunc:

def testFunc(x: HttpResponse): String = { 
    Unmarshal(x).to[String].toString 
} 

здесь типы нормально, но что вы делаете внутри, нет.

Unmarshal(x).to[String] 

возвращает Future[String] - это означает, что он является асинхронным результат, и его значение будет появляться там вовремя. Это нормально, использовать такой тип результата в flatMap.

val sqrts: Double => List[Double] = x => List(Math.sqrt(x), -Math.sqrt(x)) 
val numbers = List(4.0, 9.0, 16.0) 
numbers.flatMap(sqrts) // List(2.0, -2.0, 3.0, -3.0, 4.0, -4.0) 
// results equal to 
numbers 
    .map(sqrts) // List(List(2.0, -2.0), List(3.0, -3.0), List(4.0, -4.0)) 
    .flatten // List(2.0, -2.0, 3.0, -3.0, 4.0, -4.0) 

Здесь вы можете увидеть, что flatMap работает как карта + расплющить (кроме того, что некоторые контейнеры даже не должны быть реализованы Свести, например Future;)).

Но почему ваш testFunc не удается? В основном вы принимаете асинхронный результат (Future[String]), и вы не ждете результата - вместо этого вы вызываете toString, который печатает только какую-то бесполезную информацию (FulfilledFuture(You just accessed hello)), но не сам результат.

Чтобы обойти эту проблему вы должны сделать что-то вроде:

def testFunc(x: HttpResponse): String = { 
    Await.result(Unmarshal(x).to[String], 10.seconds) 
} 

это будет блокировать и ждать максимум в течение 10 секунд для результата, чтобы сделать его синхронным.(Этот вид превосходит цель в этом случае и map был бы более полезен, если результат, который вы вычислили, был в первую очередь синхронным.)

1

map и flatMap разница:

flatMap разрушится один уровень вложенной структуры (она называет fallten), как: List(List(1), List(2)).flatMap(i => i) будет: List(1, 2)

так как ваш код, testFlatFunc и testFuncтип возврата: Future[String] и map и flatMap функция возврат type тоже be Future[T], но flatMap будет сгладить гнездо, так: Future[Future[String]] будет flatten быть Future[String]. и map функция не будет делать это, так:

val future1:Future[String] = Http() 
    .singleRequest(
     HttpRequest(method = HttpMethods.GET, 
        uri = "http://localhost:8187/hello")).map(testFunc) 

тип возвращаемого значения должен быть:

val future1:Future[Future[String]] = Http() 
    .singleRequest(
     HttpRequest(method = HttpMethods.GET, 
        uri = "http://localhost:8187/hello")).map(testFunc)