#scala #async-await #future #either
Вопрос:
Я новичок в scala , я пытаюсь реализовать логику фильтрации поверх a 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
}
}
Я получаю ошибку для filter
функции on getTaskId
, которая возвращает Future[Try[Int]]
type mismatch;
found : scala.concurrent.Future[scala.util.Try[Int]]
required: Boolean
Так что в основном filter
поверх Future
возвращения другого Future
, но родитель filter
ожидает boolean
Мы будем очень признательны за любую помощь.
Комментарии:
1. Вопрос недостаточно ясен, чтобы ответить на него. Вы фильтруете
List[Either]
информацию ?2. Ваша функция , вероятно, должна возвращать a
Future[Either[A, B]]
вместоEither[A, B]
, потому что ваша функция асинхронна.3.@TausifSayyad да, я
filtering
List[Either]
4. @curiousguy что вы хотите получить в конце своей фильтрации? Какого типа?
5. @BorisAzanov это должно быть результатом моего фильтра
CommittableRecord[Either[Throwable,MyEvent]]
Ответ №1:
Здесь вы столкнулись с двумя сложными функциями в scala:
- Много синтаксического сахара
- Лучшая практика в 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
}
)
или, после некоторого рефакторинга и замены лямбда-выражений на функции:
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
.
Полезные ссылки:
- подробнее о будущем читайте в документации scala
- статья о лямбда-выражениях
- некоторые лучшие практики в scala одновременно