映射与返回Try [T]的函数,以返回Try [T]而不是List [Try [T]]

时间:2018-07-29 21:53:25

标签: scala exception-handling functional-programming pattern-matching

这个问题的标题有点奇怪,但是我想完成如下。

我有List的{​​{1}}。为了方便起见,任务定义如下:

Tasks

我有一个case class Task(name: String) 特性,它具有一个存储方法,该方法将持久执行任务并返回一个TaskStorage

我的存储没有批处理存储API,因此我需要在应用程序端模拟批处理存储。我最初的工作方式如下:

Try[Task]

我的API设计在这里可能有点怀疑,但我想要的是以下内容:

val tasks = List(task1, task2)
tasks.map(taskStorage) -> This returns a List[Try[Task]]

def batchStoreTasks(tasks: List[Task]):Try[Task] = { // } 指示存储设备要求保留的最后一个任务的状态。由于无法找到惯用的方法来完成上述任务,因此我求助于模式匹配并执行以下操作:

Try[Task]

我能够完成工作,但是我缺少完成上述工作的惯用方式。如果我能指出正确的方向来重组batchStoreTasks,使其具有更惯用的形状,那将是很好的选择。

谢谢

3 个答案:

答案 0 :(得分:2)

如果列表非空但所有任务均失败,则假设您要返回上一个任务的失败:

val tryTasks = tasks.map(taskStorage).reverse
tryTasks
  .find(_.isSuccess)                          // try to find a success
  .orElse(tryTasks.headOption)                // return last failure
  .getOrElse(Failure(EmptyTaskListException)) // special failure for empty list

请注意,它通常会丢弃失败任务中捕获的失败信息,但这是我从您的描述中所了解的。

答案 1 :(得分:1)

相信一个可能的解决方案,我正在使用列表上的视图来确保地图是惰性的,并且在不必要的情况下不会评估taskStorage,在示例中将仅打印任务“ A”和“ B”:

  case class Task(name: String)
  class TaskStorage {

    def apply(task: Task): Try[Task] = {
      if (task.name == "B"){
        println("Failed")
        Failure(new RuntimeException)
      }
      else {
        println("Success")
        Success(task)
      }
    }
  }
  val taskStorage: TaskStorage = new TaskStorage()
  val tasks = List(Task("A"), Task("B"), Task("C"))

  tasks.view.map(taskStorage(_)).collectFirst {
    case r if r.isFailure => r
  }.getOrElse(taskStorage(tasks.head))

在RxJava / RxScala中,可以轻松实现:

case class Task(name: String)

trait TaskStorage {
  def apply(task: Task): Try[Task]
}

val taskStorage: TaskStorage = _ //Instance of concrete task storage

def batchStoreTasks(tasks: List[Task]): Observable[Task] = {
  for {
      taskName <- Observable.from(tasks)
      taskResult <- Observable.from(taskStorage(taskName))
   } 
   yield taskResult
}

答案 2 :(得分:0)

您可以使用takeWhile

def batchStoreTasks(tasks: List[Task]): Try[Task] =
if(tasks.isEmpty) Failure(EmptyTaskListException) else {
  val tryStore = tasks.diff(tasks.takeWhile(x => taskStorage(x).isSuccess))
  tryStore.map(_ => Failure(new RuntimeException(tryStore.head.toString))).headOption.getOrElse(Success(tryStore.reverse.head))
}