遍历列表时处理 Future[Option[T]]

Handle Future[Option[T]] when traversing a List

  def getCommentIds(
      commentTargetId: Long,
      sortOrder: CommentOrderEnum): Future[Seq[CommentStatsBO]]

def getCommentDetail(commentId: Long): Future[Option[CommentDetailDTO]]

def getCommentListWithDetail(
      targetId: Long,
      sortOrder: CommentOrderEnum,
      page: Int): Future[Seq[CommentDetailDTO]] = {
    commentModel.getCommentIds(targetId, sortOrder).flatMap {
      commentStatsBOSeq =>
        Future.traverse(commentStatsBOSeq) { commentStatsBO =>
// commentDetail is a Future[Option[T]]
          val commentDetail = getCommentDetail(commentStatsBO.iId)
          commentDetail.map(commentOpt =>
            commentOpt
// merge the stat info into the comment detail
              .map(_.copy(replyCount = Some(commentStatsBO.replyCount)))
              .getOrElse(CommentDetailDTO))

        }

    }
  }

case class CommentDetailDTO(
    id: Long,
    author: JsObject,
    detail: CommentDetail,
replyCount: Option[Int] = None
)

首先,函数 getCommentIds returns CommentStatsBO 序列,然后遍历它并尝试获取每条评论的详细信息。问题来了,getCommentDetail returns一个Future,里面有一个option,因为评论可能找不到,这种情况下,如何过滤option为None的呢?我试过 getOrElse ,但不知道如何像 Json.obj() 一样定义一个空对象,因为 case class 不支持。 谢谢!

不要尝试同时做太多事情,而是逐步构建您需要的解决方案。

如果您只使用 getCommentDetail 执行简单的 Future.traverse,您将得到一个 Future[Seq[Option[CommentDetailDTO]]],然后您可以 map 并使用 collectSeq 删除 Option

def getCommentListWithDetail(
  targetId: Long,
  sortOrder: CommentOrderEnum,
  page: Int
): Future[Seq[CommentDetailDTO]] =
  commentModel.getCommentIds(targetId, sortOrder).flatMap { commentStatsBOSeq =>
    Future.traverse(commentStatsBOSeq) { commentStatsBO =>
      getCommentDetail(commentStatsBO.iId)
    } map { commentOptionalDetails =>
      commentOptionalDetails.collect {
        case Some(commentDetail) => commentDetail
      }
    }
  }

或者如果你使用 cats,你可以使用 traverseFilter

import cats.syntax.all._

def getCommentListWithDetail(
  targetId: Long,
  sortOrder: CommentOrderEnum,
  page: Int
): Future[Seq[CommentDetailDTO]] =
  commentModel.getCommentIds(targetId, sortOrder).flatMap { commentStatsBOSeq =>
    commentStatsBOSeq.traverseFilter(getCommentDetail)
  }