首页 > 解决方案 > Scala 中的嵌套过滤器要么在 Future[Try[Int]] 之上

问题描述

我是 scala 的初学者,我正在尝试在Either. 现在我有一个getTaskId返回的函数,Future[Try[Int]]我的函数filter logic就是基于它Int。现在由于filter期望boolean,我无法在下面的代码片段中返回相同的内容。

val records: List[CommittableRecord[Either[Throwable, MyEvent]]] = ???
records.filter { 
  (x: CommittableRecord[Either[Throwable,MyEvent]]) => 
    x.value match {
      case Right(event: MyEvent) =>
        getTaskId(event.get("task").get) filter {
            case Success(value)     => value > 1
            case Failure(exception) => false
          }
      case Left(_) => false
    }
}

我收到返回的filteron 函数的错误getTaskIdFuture[Try[Int]]

type mismatch;
 found   : scala.concurrent.Future[scala.util.Try[Int]]
 required: Boolean

所以基本上filter除了Future返回另一个Future但父母filter期待一个boolean

任何帮助是极大的赞赏。

标签: scalaasync-awaitfutureeither

解决方案


您在这里遇到了 scala 中的两个困难功能:

  1. 大量的语法糖
  2. scala 中的最佳实践不是Future在你内部等待一些业务逻辑的结果,使用:Await.result(future, timeout)。你应该只在宇宙的尽头使用它(在大多数情况下:在你的程序结束时)。

所以,我建议重构你当前的逻辑,从过滤List[CommittableRecord]结果中使结果是非阻塞的 -Future[List[CommittableRecord]]使用过滤的记录列表。您可以使用这个未来,就像它只是另一个数据容器(如Option[T])并在程序结束时调用阻塞操作,如Await.result.

代码示例:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future.sequence
import scala.util.{Failure, Success, Try}

case class Task()

type MyEvent = Map[String, Task]
case class CommittableRecord(value: Either[Throwable, MyEvent])

def getTaskId(task: Task): Future[Try[Int]] = ???

val records: List[CommittableRecord] = List.empty[CommittableRecord]
val result: Future[List[CommittableRecord]] = sequence(
  records.map(
    x =>
      (x.value match {
        case Left(_) => Future(false)
        case Right(value) =>
          getTaskId(value.get("task").get)
            .map {
              case Failure(_) => false
              case Success(id) => id > 1
            }
      }).map(_ -> x)
  )
).map(
  idMoreThen1AndRecordList =>
    idMoreThen1AndRecordList.collect {
      case (true, record) => record
    }
)

或者,经过一些重构并将 lambda 表达式替换为函数:

def isTaskIdMoreThenOneAndRecord(record: CommittableRecord): Future[(Boolean, CommittableRecord)] =
  (record.value match {
    case Left(_) => Future(false)
    case Right(value) =>
      getTaskId(value.get("task").get)
        .map(tryId => tryId.fold(_ => false, _ > 1))
  }).map(_ -> record)

def filterRecordsWithTaskIdMoreThenOne(
    isMoreOneAndRecordList: List[(Boolean, CommittableRecord)]
): List[CommittableRecord] =
  isMoreOneAndRecordList.collect {
    case (true, record) => record
  }

val result: Future[List[CommittableRecord]] =
  sequence(records.map(isTaskIdMoreThenOneAndRecord))
    .map(filterRecordsWithTaskIdMoreThenOne)

因此,您将拥有Future[List[CommittableRecord]]并且可以使用map以下函数处理过滤后的记录:

result.map((filteredRecords: List[CommittableRecord]) => \*do something with filtered records*\)

或者您可以使用flatMap.

有用的链接:


推荐阅读