我有一个问题涉及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”?
答案 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
}