Scala将Future [IOResult]映射到Future [Unit]

时间:2018-08-24 13:02:33

标签: scala

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

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

我想在我的函数中检查Future和IOResult的成功和失败,但是仅从此函数返回Failure [Unit],这可能吗?

下面的代码报告错误:

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)
    }
  }

3 个答案:

答案 0 :(得分:4)

三件事。

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

  2. 您赋予recover的函数应该返回实际结果,而不是FuturerecoverWith适用于期货)。

  3. 您赋予map的函数也返回实际结果。如果您确实需要返回flatMap

  4. ,则需要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
  }

答案 1 :(得分:0)

这可能有效:

  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将使Future语句返回的嵌套match变平,并且recover现在返回Unit,因此结果为Future[Unit]recover将捕获所有生成的错误,因此您无需在内部Failure情况下打印任何内容。

答案 2 :(得分:0)

您要返回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 { _ => () }