尝试失败时短路映射操作
Short circuit Map Operation If Try Fails
我有这样的功能:
def foo(item: Item) : Option[Int] = Try{
// Some code that can blow up
}.toOption
我有一个项目列表,我想通过它们进行映射,并应用上述功能。但是如果上面的函数爆炸了并且 returns a None 那么 map 的结果应该是一个错误:
items.map{
item => foo(item)
}
地图不适合在这里做吗?好像不是
这叫做traverse
。如果可以使用cats,就这么简单:
import cats.implicits._
val result = items.traverse(foo) // Option[List[Int]]
如果没有,您可以很容易地实现它:
def traverse[A, B](data: List[A])(f: A => Option[B]): Option[List[B]] = {
@annotation.tailrec
def loop(remaining: List[A], acc: List[B]): Option[List[B]] =
remaining match {
case a :: as => f(a) match {
case Some(b) => loop(remaining = as, b :: acc)
case None => None
}
case Nil => Some(acc.reverse)
}
loop(remaining = data, acc = List.empty)
}
你可以像这样使用:
val result = traverse(items)(foo) // Option[List[Int]]
(但是,我建议您改用 cats,因为它更通用).
对于开箱即用的短路,考虑像这样用 Try
包装列表映射
def fooUnsafe(item: Item): Int = // might throw
Try(items.map(fooUnsafe))
如果你想保留def foo(item: Item) : Option[Int]
签名那么下面也会短路
Try(list.map(v => foo(v).get))
我有这样的功能:
def foo(item: Item) : Option[Int] = Try{
// Some code that can blow up
}.toOption
我有一个项目列表,我想通过它们进行映射,并应用上述功能。但是如果上面的函数爆炸了并且 returns a None 那么 map 的结果应该是一个错误:
items.map{
item => foo(item)
}
地图不适合在这里做吗?好像不是
这叫做traverse
。如果可以使用cats,就这么简单:
import cats.implicits._
val result = items.traverse(foo) // Option[List[Int]]
如果没有,您可以很容易地实现它:
def traverse[A, B](data: List[A])(f: A => Option[B]): Option[List[B]] = {
@annotation.tailrec
def loop(remaining: List[A], acc: List[B]): Option[List[B]] =
remaining match {
case a :: as => f(a) match {
case Some(b) => loop(remaining = as, b :: acc)
case None => None
}
case Nil => Some(acc.reverse)
}
loop(remaining = data, acc = List.empty)
}
你可以像这样使用:
val result = traverse(items)(foo) // Option[List[Int]]
(但是,我建议您改用 cats,因为它更通用).
对于开箱即用的短路,考虑像这样用 Try
包装列表映射
def fooUnsafe(item: Item): Int = // might throw
Try(items.map(fooUnsafe))
如果你想保留def foo(item: Item) : Option[Int]
签名那么下面也会短路
Try(list.map(v => foo(v).get))