Фьючерсы Scala, использующие Future.sequence, но имеющие проблемы с возвратом кортежа

#scala #future

#scala #будущее

Вопрос:

У меня возникли некоторые проблемы при попытке вернуть кортеж, когда я использую Future.sequence ниже:

 type UserId = Int
  type GameId = Int
  type Score = Double

  case class Game(id: GameId)

  def findGame(id: GameId): Future[Game] = ???
  def findUserGames(id: UserId): Future[Seq[(GameId, Score)]] = ???

  def findGames(id: UserId): Future[Seq[(Game, Score)]] = {
    val userGames = findUserGames(id)

    // ******* I am stuck here
    val games: Future[Seq[Game]] = userGames.flatMap(x => Future.sequence(x.map(y => findGame(y._1))))    
  }
 

Как я могу вернуть кортеж (Game, Score) , когда вызов Future.sequence просто возвращает мне a Seq[Game] ?

Кроме того, если бы у нас не было Future.sequence , как бы мы могли имитировать то, что он делает? т. Е. Преобразование a List[Future[Game]] в a Future[List[Game]] ?

Комментарии:

1. Попробуйте использовать Future.traverse вместо Future.sequence , так как это более эффективно.

Ответ №1:

Вы можете попробовать это:

 def findGames(id: UserId): Future[Seq[(Game, Score)]] = {
  findUserGames(id).flatMap(gameIdToScoreSeq =>
    Future.traverse(gameIdToScoreSeq)(gameIdToScore =>
      findGame(gameIdToScore._1).map((_, gameIdToScore._2))
    )
  )
}
 

Ответ №2:

просто отслеживая, что есть что по имени, как oneliner, вы можете сделать

 def findGames(id: UserId)(implicit ec: ExecutionContext): Future[Seq[(Game, Score)]] =
  findUserGames(id).flatMap(games =>
    Future.sequence(games.map { case (gameid, score) =>
      findGame(gameid).map(game => game -> score)
    })
  )
 

Ответ №3:

Вам просто нужна еще одна карта:

 val games: Future[Seq[(Game, Score)]] = userGames.flatMap(x => Future.sequence(x.map(y => findGame(y._1).map(z => (z, y._2)))))
 

Как вы можете видеть, это становится немного запутанным. Вы могли бы сделать свой код более читаемым (возможно), используя for-comprehensions и сопоставление с образцом:

 val games2: Future[Seq[(Game, Score)]] = for {
  games <- userGames
  result <- Future.sequence(games.map {
    case (gameId, score) => 
      for {
        game <- findGame(gameId)
      } yield (game, score)
  })
} yield result