首页 > 解决方案 > 当容器项是 Either 时如何组合期货

问题描述

当我的返回值 whereEither[String, User]Either[String, Seq[Sale]].

我的函数实际上返回期货,所以一旦我将它们包装在期货中,我就会面临问题。

当内部容器为 Either 类型时,我需要有关如何组合 Futures 的帮助。

注意:我将不得不对销售集合执行进一步的业务逻辑,但到目前为止我需要的总体大纲如下:

import scala.concurrent._
import ExecutionContext.Implicits.global


case class User(id: Int)
case class Sale(id: Int)

case class Response(user: User, sales: Seq[Sale])

def getUser(id: Int): Future[Either[String, User]] = Future(Right(User(123)))
def getSales(userId: Int): Future[Either[String, Seq[Sale]]] = Future(Right(Seq(Sale(1), Sale(2))))

val response = for {
  user <- getUser(123)
  sales <- getSales(user.id)
} yield Response(user, sales)

println(response)

我在 playframework 操作方法中执行此操作:

def getUser(id: Int) = Action.async {

   val response = for {
      user <- getUser(123)
      sales <- getSales(user.id)
    } yield Response(user, sales)

  Ok(response) // gets converted to JSON
}

标签: scalaplayframework

解决方案


如果你不能使用猫,那么你必须自己实现变压器。这是一个示例Either[String,_]:(链接到 Scastie

import scala.concurrent._
import ExecutionContext.Implicits.global
   
case class FutureEither[A](value: Future[Either[String,A]]){
  def map[B](f: A => B)(implicit ec: ExecutionContext): FutureEither[B] = FutureEither(value.map(_.map(f)))
  def flatMap[B](f: A => FutureEither[B])(implicit ec: ExecutionContext): FutureEither[B] = FutureEither(value.flatMap{
    case Left(s) => Future.successful(Left(s))
    case Right(a) => f(a).value
  })
}

case class User(id: Int)
case class Sale(id: Int)    
case class Response(user: User, sales: Seq[Sale])

def getUser(id: Int): Future[Either[String, User]] = Future(Right(User(123)))
def getSales(userId: Int): Future[Either[String, Seq[Sale]]] = Future(Right(Seq(Sale(1), Sale(2))))

val response = for {
  user <- FutureEither(getUser(123))
  sales <- FutureEither(getSales(user.id))
} yield Response(user, sales)

println(response.value.onComplete(println(_)))

请注意,您可以轻松地对 wrapping 进行抽象Future[_]。它只需要是一个单子(需要有mapflatMapapply方法)。如果你这样做,并添加更多的语法细节,你最终会得到EitherTfrom cat 。


推荐阅读