Scala 映射未来[IOResult] to Future[Unit]



我有一个函数必须返回一个 Future[Unit]。

在我的函数中,我正在编写一个返回 Future[IOResult] 的文件。未来和 IOResult 都可能具有故障状态。

我想在我的函数中检查未来和 IOResult 的成功和失败,但只需从此函数返回一个故障[单元],这可能吗?

下面的代码报告错误:

discarded non-Unit value
[error]           Future.successful(Unit)
discarded non-Unit value
[error]           Future.failed(e)

这是我的函数:

def create(filePath: String, fileStream: Source[ByteString, Any]): Future[Unit] = {
val writeResultFuture: Future[IOResult] = fileStream.runWith(FileIO.toPath(filePath))
writeResultFuture map { writeResult =>
writeResult.status match {
case Success(_) =>
logger.info(s"Successfully uploaded: ${fileInfo.fileName} to: $filePath")
Future.successful(Unit)
case Failure(e) =>
logger.error(s"Failed to upload: ${fileInfo.fileName} to: $filePath", e)
Future.failed(e)
}
} recover {
case e =>
logger.error(s"Failed to upload: ${fileInfo.fileName} to: $filePath", e)
Future.failed(e)
}
}

三件事。

  1. Unit不是Unit类型的值(它是对 scala 库中定义的object scala.Unit的引用(。您希望()表示值Unit

  2. 你给recover的函数应该返回实际结果,而不是Future(recoverWith适用于期货(。

  3. 您提供给map的函数也会返回实际结果。您需要flatMap是否真的需要返回Future

所以,这样的事情应该有效:

writeResultFuture.map { writeResult =>
writeResult.status match {
case Success(_) =>
logger.info(s"Successfully uploaded: ${fileInfo.fileName} to: $filePath")
case Failure(e) =>
logger.error(s"Failed to upload: ${fileInfo.fileName} to: $filePath", e)
throw e
}
}.recover { case e =>
logger.error(s"Failed to upload: ${fileInfo.fileName} to: $filePath", e)
throw e
}

更好的是,使用onFailure而不是recover- 这样你就不需要重新抛出。只要做.onFailure { e => logger.error(...) }另外,请注意,您以这种方式记录错误两次(一次在map内,然后在recover/onFailure中再次记录错误(...考虑完全卸下recover部件。

writeResultFuture.map(_.status).map { 
case Success(_) => logger.info(s"Successfully uploaded: ${fileInfo.fileName} to: $filePath")
case Failure(e) => logger.error(s"Failed to upload: ${fileInfo.fileName} to: $filePath", e)
throw e
}

这可能有效:

writeResultFuture flatMap { writeResult =>
writeResult.status match {
case Success(_) =>
logger.info(s"Successfully uploaded: ${fileInfo.fileName} to: $filePath")
Future.successful()
case Failure(e) =>
Future.failed(e)
}
} recover {
case e =>
logger.error(s"Failed to upload: ${fileInfo.fileName} to: $filePath", e)
}

使用flatMap将展平match语句返回的嵌套Futurerecover现在返回Unit以便结果Future[Unit]recover将捕获生成的所有错误,因此您无需在内部Failure的情况下打印任何内容。

您返回的是 Future,因此您的最终结果将是 Future[Future[...]] 类型,在您的情况下,我们根本不需要嵌套,因此我们可以将代码更改为:

免责声明:我只在这里输入了代码,它没有经过类型检查,YMMV。无担保。等等

等等
fileStream.runWith(FileIO.toPath(filePath)) transform {
case Failure(e) => Failure(e)
case Success(i: IOResult) => i.status
} andThen {
case Success(_) =>
logger.info(s"Successfully uploaded: ${fileInfo.fileName} to: $filePath")
case Failure(e) =>
logger.error(s"Failed to upload: ${fileInfo.fileName} to: $filePath", e)
}
} map { _ => () }

最新更新