使用 returns Try[T] 到 return Try[T] 而不是 List[Try[T]] 的函数映射
Mapping with a function that returns Try[T] to return a Try[T] instead a List[Try[T]]
这个问题的标题有点奇怪,但我想完成如下。
我有 List
个 Tasks
。为了方便任务定义如下:
case class Task(name: String)
我有一个 TaskStorage
特征,它有一个存储方法,可以持久保存任务,return 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 以赋予它更惯用的形状,那就太好了。
谢谢
假设您想要 return 如果列表非空但所有任务都失败,则最后一个任务失败:
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
请注意,它通常会丢弃失败任务中捕获的失败信息,但这是我从您的描述中了解到的。
你可以使用 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))
}
Belw 一个可能的解决方案,我在列表上使用视图来确保地图是惰性的,并且 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
}
这个问题的标题有点奇怪,但我想完成如下。
我有 List
个 Tasks
。为了方便任务定义如下:
case class Task(name: String)
我有一个 TaskStorage
特征,它有一个存储方法,可以持久保存任务,return 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 以赋予它更惯用的形状,那就太好了。
谢谢
假设您想要 return 如果列表非空但所有任务都失败,则最后一个任务失败:
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
请注意,它通常会丢弃失败任务中捕获的失败信息,但这是我从您的描述中了解到的。
你可以使用 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))
}
Belw 一个可能的解决方案,我在列表上使用视图来确保地图是惰性的,并且 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
}