将标题添加到seq

时间:2017-07-04 13:36:56

标签: scala playframework

我有一个问题涉及scala中的范围。我有这样的功能:

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:你好嗨 为什么scala这样做?我会假设第一次执行第三次打印。当我到达“FirstPrint”时,“hi”已经消失了。为什么最后一行代码先执行? 我正在使用光滑和期货,这与它有关吗?谢谢!

更新

谢谢,工作正常。 是否可以返回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
  }

每当idsAsElements为“onComplete”时,是否可以返回“mySequence”?

2 个答案:

答案 0 :(得分: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:你好嗨嗨

ThirdPrint:你好嗨嗨

SecondPrint:你好嗨嗨

FirstPrint:你好嗨嗨

答案 1 :(得分:1)

是的,这不是一个好的解决方案。您应该避免在代码中阻塞,除非可能在最高级别(main方法)。此外,可变状态很糟糕,尤其是当与并发(期货)结合时。

您的函数应返回Future。这样的东西会起作用(我不确定我是否正确地猜测了你的代码的意图 - 你的函数被声明为返回Seq[Element],但写的是为了返回Unit ...我假设,那是什么你真的想要返回的是每个id getElement调用的结果:

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

我删除了你的打印输出,因为他们不确定他们服务的目的是什么(因为对dto.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
  }