尝试失败时短路映射操作

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))