【问题标题】:Handle Future[Option[T]] when traversing a List遍历列表时处理 Future[Option[T]]
【发布时间】:2021-12-13 16:16:19
【问题描述】:
  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返回一个CommentStatsBO序列,然后遍历它并尝试获取每个评论的详细信息。问题来了,getCommentDetail 返回一个 Future ,其中包含一个选项,因为可能找不到评论,在这种情况下,如何过滤那些选项为 None 的?我试过getOrElse ,但不知道如何定义一个像Json.obj() 一样的空对象,因为case class 不支持。 谢谢!

【问题讨论】:

  • 顺便说一句,未来的相遇选项会变成悲剧。现在我发现 scala 的未来对程序员来说仍然很详尽。

标签: scala future optional


【解决方案1】:

不要试图同时做太多事情,而是一步一步构建你需要的解决方案。

如果您只使用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)
  }

【讨论】:

  • 非常感谢兄弟!你的答案是进步的,尤其是后者是如此优雅和简洁!该死的,我没有足够的声望来投票。一旦我在声誉上变得富有,我会回到你的答案:)
  • 我发现commentOptionalDetails => commentOptionalDetails.collect { case Some(commentDetail) => commentDetail }可以替换为commentOptionalDetails => commentOptionalDetails.flatten。在scala中将Seq[Option[T]]转换为Seq[T]是一种更方便的方式。
  • @BugSource 不用担心,我很高兴它对您有所帮助 :) 如果您对 cats 感兴趣,请查看 “Scala with Cats” 一书。 - 关于flatten,你是对的,我总是忘记那个,因为我有点不喜欢这样的选项有效;但这只是个人意见,如果您更喜欢那一个继续:)
  • 我同意你的观点。并不是说程序越短,程序员就越快乐,尤其是对于那些阅读和维护它们的人来说。我是 scala 的新手,但在我看来,现在 scala 很难在简洁和可读性之间找到平衡。 Java比较冗长,但至少大家都能看懂……
猜你喜欢
  • 2016-11-08
  • 2014-11-19
  • 1970-01-01
  • 2015-10-09
  • 1970-01-01
  • 2023-01-14
  • 1970-01-01
  • 1970-01-01
  • 2015-11-03
相关资源
最近更新 更多