2017-07-04 4 views
0

スケーラでのスコープに関する質問があります。私はこのような機能を持っている:スケーラのタイミングで問題が発生する場合があります。

def getElements(id: Int): Seq[Element] = { 
    var test = "" 
    dto.getElementIds(id).map { 
     elementIds => { 
     test += " hello " 
     elementIds.foreach(elementId => dto.getElement(elementId).map { 
      case Some(element) => test += " hi " 
       println("ThirdPrint: " + test) 
     }) 
     println("SecondPrint: " + test) 
     } 
    } 
    println("FirstPrint: " + test) 
} 

は "elementsIds" と言うことができます。2. のな長さを有するコンソールは言う: FirstPrint: SecondPrint:こんにちは ThirdPrint:こんにちはこんにちは ThirdPrint:こんにちはこんにちはこんにちは なぜそれはスカラーですか?私は3番目の印刷が最初に実行されると仮定します。私が "FirstPrint"に行くとき、 "hi"はなくなってしまいました。コードの最後の行が最初に実行されるのはなぜですか? 私は滑らかな先物と一緒に働いていますが、これには関係がありますか?ありがとう!

UPDATE

おかげで、正常に動作します。 代わりにseqを返すことはできますか?このように:

def getElements(id: Int): Future[Seq[Element]] = { 
    var mySequence: Seq[Element] = Seq() 
    val elementsIds: Future[Seq[Int]] = dto.getElementIds(id) 
    var test = "" 
    val elementsF = elementsIds.flatMap { 
     elementIds => { 
     test += " hello " 
     val idsAsElements: Seq[Future[Element]] = elementIds.map(elementId => dto.getElement(elementId).collect { 
      case Some(element) => mySequence = mySequence :+ element 
     }) 
     val idsAsElementsF: Future[Seq[Element]] = Future.sequence(idsAsElements) 
     idsAsElementsF.onComplete(_ => println("SecondPrint: " + test)) 
     idsAsElementsF 
     } 
    } 
    elementsF.onComplete(_ => println("FirstPrint: " + test)) 
    elementsF 
    } 

idsAsElementが "onComplete"のときはいつでも "mySequence"を返すことはできますか?

+0

は 'dto.getElementIds(ID)' 'Future'を返しますか?あなたはそのタイプを提供できますか? –

+0

はい未来[Seq [Int]] – Felix

+0

これは、バックグラウンドで並列スレッドで実行されています。あなたの 'FirstPrint'が行頭で実行されている間に、他のスレッドはそれらのIDを取得する場所からこれらのIDを取得する作業をしています。一度起これば、' .map'が実行されます。 – Dima

答えて

1
object X { 
    import scala.concurrent.ExecutionContext.Implicits.global 
    case class Element() 
    object dto{ 

    def getElementIds(i: Int): Future[Seq[Int]] = Future(Seq(1,2,3)) 
    def getElement(i: Int): Future[Option[Element]] = Future(Some(Element())) 

    } 

    def main(args: Array[String]): Unit = { 
    getElements(0) 
    Thread.sleep(10000) // waiting logs 
    } 
    def getElements(id: Int): Future[Seq[Element]] = { 
    val elementsIds: Future[Seq[Int]] = dto.getElementIds(id) 
    var test = "" 
    val elementsF = elementsIds.flatMap { 
     elementIds => { 
     test += " hello " 
     val idsAsElements: Seq[Future[Element]] = elementIds.map(elementId => dto.getElement(elementId).collect { 
      case Some(element) => test += " hi " 
      println("ThirdPrint: " + test) 
      element 
     }) 
     val idsAsElementsF: Future[Seq[Element]] = Future.sequence(idsAsElements) 
     idsAsElementsF.onComplete(_ => println("SecondPrint: " + test)) 
     idsAsElementsF 
     } 
    } 
    elementsF.onComplete(_ => println("FirstPrint: " + test)) 
    elementsF 
    } 
} 

出力:

ThirdPrint:

ThirdPrint HI HIこんにちは:こんにちはHI HI HI

SecondPrint:

ThirdPrint HIハローハローHI、HI、HI

FirstPrint:hello hi hi hi

+0

.mapを使用している場合、すべてのケースをカバーする必要があることを忘れないでください。 .map { )=> ...}が失敗した場合 – Ivan

+0

最初の完成したidsAsElementを関数から受け取って他のものをスキップしますか? – Ivan

+0

戻り値(Some(element))を次のように追加したいとします: 'mySequence = mySequence:+ (要素ID)=要素dI.getElement(要素ID)。コレクタ{...} ' を返し、終了後にそのリストを返します。 – Felix

1

はい、それは良い解決策ではありません。おそらく可能な限り高いレベル(mainメソッド)を除いて、コード内でブロックしないでください。また、同時実行性(先物)と組み合わされたとき、可変状態は悪いものです。

関数はFutureを返します。このようなものがうまくいくでしょう(あなたのコードの意図を正しく見ればわかりません - あなたの関数はSeq[Element]を返すと宣言されましたが、Unitを返すように書かれています...)

def getElements(id: Int): Future[Seq[Element]] = dto 
    .getElementIds(id) 
    .map { ids => ids.map(dto.getElement) } 
    .flatMap(Future.sequence) 
    .map(_.flatten) 

dto.getElementへの呼び出しも並行して起こっているので、(彼らが提供目的だったのかわからなかった、それはどこ明らかにされていませんので、私は、あなたのプリントアウトを削除:すべてのidのgetElement通話)のどのような順序でそれらの文字列を印刷したいか)。

あなたは、たとえば最後に別の変換を追加することで、あなたの "期待される出力" をシミュレートすることができます:

.andThen { case Success(results) => 
    val str = results.foldLeft("hello") { case (a,b) => 
     println("ThirdPrint: " + a + " hi") 
     a + " hi" 
    } 
    println("SecondPrint: " + str) 
    println("FirstPrint: " + str 
    } 
関連する問題