我已经阅读了有关map
和flatMap
的文档,并且我了解flatMap
用于接受Future
参数并返回另一个Future
的操作。我不完全理解的是为什么我要这样做。举个例子:
我了解我希望以后使用它来下载文件,但是我有两个选择来对其进行重新处理:
val downloadFuture = Future {/* downloadFile */}
val processFuture = downloadFuture map {/* processFile */}
processFuture onSuccess { case r => renderResult(r) }
要么
val downloadFuture = Future {/* download the file */}
val processFuture = downloadFuture flatMap { Future {/* processFile */} }
processFuture onSuccess { case r => renderResult(r) }
通过添加调试语句(
Thread.currentThread().getId
),我发现在两种情况下,process
和render
都在同一线程中发生(使用ExecutionContext.Implicits.global
)。我是否会简单地使用
flatMap
解耦downloadFile
和processFile
,并确保processFile
始终在Future
中运行,即使它不是从downloadFile
映射的也是如此?
最佳答案
ensure that
processFile
always runs in aFuture
even if it was not mapped fromdownloadFile
?
对,那是正确的。
但是,大多数情况下,您不会直接使用
Future { ... }
,而是会使用返回Future
的函数(来自其他库或您自己的函数)。想象以下功能:
def getFileNameFromDB{id: Int) : Future[String] = ???
def downloadFile(fileName: String) : Future[java.io.File] = ???
def processFile(file: java.io.File) : Future[ProcessResult] = ???
您可以使用
flatMap
组合它们:val futResult: Future[ProcessResult] =
getFileNameFromDB(1).flatMap( name =>
downloadFile(name).flatMap( file =>
processFile(file)
)
)
或使用来理解:
val futResult: Future[ProcessResult] =
for {
name <- getFileNameFromDB(1)
file <- downloadFile(name)
result <- processFile(file)
} yield result
大多数情况下,您不会调用
onSuccess
(或onComplete
)。通过使用这些函数之一,您可以注册一个回调函数,该函数将在Future
完成时执行。如果在我们的示例中,您想呈现文件处理的结果,则将返回类似
Future[Result]
的内容,而不是调用futResult.onSuccess(renderResult)
。在最后一种情况下,您的返回类型将为Unit
,因此您无法真正返回任何内容。在Play Framework中,它可能类似于:
def giveMeAFile(id: Int) = Action.async {
for {
name <- getFileNameFromDB(1)
file <- downloadFile(name)
processed <- processFile(file)
} yield Ok(processed.byteArray).as(processed.mimeType))
}
关于scala - future - map 与平面图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31641190/