簡體   English   中英

使用返回Try [T]的函數進行映射以返回Try [T]而不是List [Try [T]]

[英]Mapping with a function that returns Try[T] to return a Try[T] instead a List[Try[T]]

這個問題的標題有點奇怪,但我想完成如下。

我有一個Tasks List 為方便起見,任務定義如下:

case class Task(name: String)

我有一個帶有存儲方法的TaskStorage特性,該方法將持久保存任務並返回Try[Task]

我的存儲沒有批量存儲API,因此我需要在應用程序端模仿批量存儲。 我最初的做法如下:

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

我的API設計可能有點懷疑,但我想要的是如下:

def batchStoreTasks(tasks: List[Task]):Try[Task] = {
   //
}

Try[Task]指示存儲要求保留的最后一個任務的狀態。 由於我無法找到完成上述任務的慣用方法,因此我采用了模式匹配並執行了以下操作:

def batchStoreTasks(tasks: List[Task]): Try[Task] = tasks match {
   case Nil => Failure(EmptyTaskListException)
   case x :: Nil => taskStorage(x)
   case x :: t => val storedTask = taskStorage(x); if(storedTask.isSuccess) batchStoreTasks(t) else storedTask

}

我能夠完成工作,但我錯過了完成上述工作的慣用方法。 如果我可以指向正確的方向來重構batchStoreTasks以使其具有更加慣用的形狀,那將是很棒的。

謝謝

如果列表非空但所有任務都失敗,則假設您要返回上一個任務的失敗:

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

請注意,它通常會丟棄在失敗任務中捕獲的失敗信息,但這是我從您的描述中理解的。

假設一個可能的解決方案,我使用列表上的視圖來確保地圖是懶惰的,並且在執行后不會評估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
}

你可以使用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))
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM