在Scala中返回特定类型的yield

时间:2015-10-17 20:58:21

标签: scala yield for-comprehension

我正在尝试使用函数异步调用3个单独的API并将响应整理到UserDetails对象中,并将其作为函数的一部分返回。

但是,我遇到的问题是,当我将返回类型显式设置为Future[UserDetails]时,它不会编译,因为yield的返回不是UserDetails对象而我我不知道如何从这里得到我想要的东西。

注意我希望返回Future[UserDetails],但推断的返回类型为Future[Object]

我的代码目前如下:

def getUserDetails(userId: String) = {
  usersConnector.getUserById(userId).map {
    case Some(user) =>
      for {
        connections <- connectionsConnector.getAllConnections(user.username) recover {case _ => None}
        pendingConnections <- connectionsConnector.getAllPendingConnections(user.username) recover {case _ => None}
        userLocation <- userLocationsConnector.getLocationByUsername(user.username) recover {case _ => None}
      } yield {
        UserDetails(Some(user), connections, pendingConnections, userLocation)
      }
    case None => UserDetails(None, None, None, None)
  }
}

1 个答案:

答案 0 :(得分:4)

问题是map函数中的情况不会返回相同的类型。 None案例会返回UserDetails。但是,Some案例会返回Future[UserDetails]。这两种类型的最小上限(最不共同的祖先)是AnyRef,即Object。因此,map函数会将Future[Option[User]]转换为Future[Object]

有两种方法可以解决这个问题。首先是两个使用Future.successful案例中的None构造函数:

...
case None => Future.successful(UserDetails(None, None, None, None))
...

现在,生成的未来类型为Future[Future[UserDetails]]。你只需要在这一点上展平它:

...
}.flatMap(x => x) // add at the end

第二种更优雅的方式是将所有内容嵌入到理解中:

def getUserDetails(userId: String) = {
  def detailsFor(user: Option[User]) = user match {
    case Some(user) =>
      for {
        connections <- connectionsConnector.getAllConnections(user.username) recover {case _ => None}
        pendingConnections <- connectionsConnector.getAllPendingConnections(user.username) recover {case _ => None}
        userLocation <- userLocationsConnector.getLocationByUsername(user.username) recover {case _ => None}
      } yield {
        UserDetails(Some(user), connections, pendingConnections, userLocation)
      }
    case None => Promise.successful(UserDetails(None, None, None, None))
  }
  for {
    user <- usersConnector.getUserById(userId)
    userDetails <- detailsFor(user)
  } yield userDetails
}

编辑:

请参阅下面的Łukasz关于在for-comprehension中异步启动期货的评论。