遍历列表时处理 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
并使用 collect
和 Seq
删除 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)
}
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
并使用 collect
和 Seq
删除 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)
}