【问题标题】:Idiomatic way to handle side effect and return value in Scala functions在 Scala 函数中处理副作用和返回值的惯用方法
【发布时间】:2017-10-25 17:59:18
【问题描述】:

如何构造一个既要产生副作用又要返回值的函数? 例如我想要以下函数:

def futureFromHttpCall: Future[HttpResponse] = 
  doHttpCall.foreach(publishDomainEvent).returnOriginalFuture

(不知何故,我觉得单子会出现,所以如果那是我对猫有点熟悉的路径,如果那里有解决这个问题的方法?)

【问题讨论】:

  • 你想要做一些副作用作为未来返回的结果,然后返回相同的未来?
  • 是的就是这样
  • publishDomainEvent 是我假设的Unit 返回方法?
  • 是的,例如actorSystem.eventStream.publish(SessionCreated)

标签: scala monads scala-cats


【解决方案1】:

我能想到的最简单的事情是,与其在Future[T] 返回方法中“隐藏”副作用,不如将其公开为未来的延续:

def futureFromHttpCall: Future[HttpResponse] = doHttpCall

然后你可以onComplete 作为副作用:

futureFromHttpCall.onComplete {
    case Success(_) => publishDomainEvent
    case Failure(e) => // Stuff
}

使效果明确。或者如果你在一个actor系统中,你可以pipeToFuture到你的receive方法并在那里处理成功/失败。

【讨论】:

    【解决方案2】:

    我认为只有在推送所有域事件时,您的 Future 才能完成。它们也应该是Future。然后你可以使用Future.sequence 等待它们全部完成后再返回。

    您的问题有点不清楚,但我认为 doHttpCall 是某种类型的列表。

    def doHttpCall(): Future[Seq[X]] = ???
    
    def publishDomainEvent(x:X): Future[Unit] = ???
    
    def futureFromHttpCall(): Future[Seq[X]] = {
    
      val firstFuture = ???
    
      firstFuture.flatMap { xs =>
        val xxs: Seq[Future[Unit]]= xs.map(publishDomainEvent)
        Future.sequence(xxs).map { _ => re }
      }
    }
    

    所有这些等待在测试时都非常有用。

    【讨论】:

    • 我喜欢这个,只是将我的域事件包装在未来
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-07
    • 1970-01-01
    • 2018-03-30
    • 2014-04-25
    • 2013-11-16
    • 2022-01-06
    相关资源
    最近更新 更多