简体   繁体   English

Scala 中的嵌套过滤器或者在 Future[Try[Int]] 之上

[英]Nested Filter in Scala Either on top of Future[Try[Int]]

I am beginner is scala , I am trying to implement a filter logic on top of a Either .我是初学者斯卡拉,我想实现在顶部的过滤逻辑Either Now I have a function getTaskId that returns Future[Try[Int]] and my filter logic is based on that Int .现在我有一个函数getTaskId返回Future[Try[Int]]并且我的filter logic基于该Int Now since filter expects boolean , I am unable to return the same in below code snippet .现在由于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
    }
}

I am getting the error for filter on function getTaskId that returns Future[Try[Int]]我在返回Future[Try[Int]]函数getTaskIdgetTaskId filter错误

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

So basically filter on top of Future returning another Future but the parent filter is expecting a boolean所以基本上在Future之上filter返回另一个Future但父filter期待一个boolean

Any help is greatly appreciated.任何帮助是极大的赞赏。

You faced two difficult features in scala here:您在这里遇到了 Scala 中的两个困难功能:

  1. A lot of syntactic sugar很多语法糖
  2. Best practice in scala is not awaiting Future s result inside you some business logic using: Await.result(future, timeout) . Scala 中的最佳实践不是等待Future的结果在您内部使用以下业务逻辑: Await.result(future, timeout) You should use it only at the end of the universe (in most cases: at the end of your program).您应该只在 Universe 的末尾使用它(在大多数情况下:在程序的末尾)。

So, I would advice to refactor your current logic from having filtered List[CommittableRecord] in result to make result is non-blocking - Future[List[CommittableRecord]] with filtered list of records.因此,我建议重构您当前的逻辑,使结果过滤List[CommittableRecord]使结果是非阻塞的 - Future[List[CommittableRecord]]带有过滤的记录列表。 You can work with this future, like it's just another data-container (like Option[T] ) and at the end of your program call blocking operation like Await.result .你可以使用这个未来,就像它只是另一个数据容器(比如Option[T] ),并且在你的程序调用阻塞操作的末尾,比如Await.result

Example of code:代码示例:

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
    }
)

or, after some refactoring and replacing lambda-expressions to functions:或者,经过一些重构并将 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)

So, in result you will have Future[List[CommittableRecord]] and you can work with filtered records using map function:因此,结果您将拥有Future[List[CommittableRecord]]并且您可以使用map函数处理过滤记录:

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

or you can compose two non-blocking operations (for example your list and another non-blocking function) using flatMap .或者您可以使用flatMap组合两个非阻塞操作(例如您的列表和另一个非阻塞函数)。

Useful links:有用的链接:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM